这里列出了每天的题单
Day1
题目地址
A: 待更
B: CF808F Card Game
题意:有n张卡片,每张卡片有能力值\(p\),魔力值\(c\),等级\(l\).
现在\(Vova\)的等级是k,她可以选择等级\(\leq k\)的卡牌使用。其中,对于所有她使用的卡牌,要保证任意两张卡牌魔力值之和不是质数。
她想让她选的卡片能力值总和\(\geq x\),求她的等级最小为多少。
解法:
首先转为二分答案,即为判断一个等级最多可以拿能力值总和为多少的卡片。
首先,两个数的和为质数,这两个数除了和为2的情况,剩下的情况都是一奇一偶。也就是说对于普遍情况,奇数和奇数不可能连边,偶数和偶数不可能连边,所以这建出边来,就是一个二分图。
先特判掉两个1的情况。只需要取能力值最大的一个1即可。否则可能就不是二分图了。
接着即为二分图最大点权独立集,求解即可。(《训练指南》P367)
#include <bits/stdc++.h>
#define dbg(x) cerr << #x " = " << x << "\n"
#define INF 0x3f3f3f3f
typedef long long ll;
typedef long double ld;
typedef unsigned long long ULL;
using namespace std;
template < typename T > inline void inp(T& t) {
char c = getchar(); T x = 1; t = 0; while(!isdigit(c)) {if(c == '-') x = -1; c = getchar();}
while(isdigit(c)) t = t * 10 + c - '0' , c = getchar();t *= x;
}
template < typename T , typename... Args > inline void inp(T& t , Args&... args) {inp(t); inp(args...);}
template < typename T > inline void outp(T t) {
if(t < 0) putchar('-') , t = -t; T y = 10 , len = 1;
while(y <= t) y *= 10 , len++; while(len--) y /= 10 , putchar(t / y + 48) , t %= y;
}
template < typename T > inline T mul(T x , T y , T MOD) {x=x%MOD,y=y%MOD;return ((x*y-(T)(((ld)x*y+0.5)/MOD)*MOD)%MOD+MOD)%MOD;}
const ll Maxn = 200000 + 10;
ll n , k , s , t;
ll p[Maxn] , c[Maxn] , l[Maxn];
struct Edge {
ll v , w , nxt , flow;
}e[Maxn << 1];
ll head[Maxn << 1] , gg[Maxn << 1] , d[Maxn] , cnt = 0;
int notp[Maxn];
bool vis[Maxn];
void Link(ll u , ll v , ll w) {
e[cnt] = (Edge){v , w , head[u] , 0} , head[u] = cnt++;
e[cnt] = (Edge){u , 0 , head[v] , 0} , head[v] = cnt++;
}
bool bfs() {
queue <ll> q;
while(!q . empty()) q . pop();
for(ll i = 0; i <= n + 10; i++) d[i] = 0 , gg[i] = head[i];
q . push(s);
d[s] = 1;
while(!q . empty()) {
ll u = q . front(); q . pop();
// cout << u << endl;
for(ll i = head[u]; i != -1 ; i = e[i] . nxt) {
ll v = e[i] . v , w = e[i] . w , flow = e[i] . flow;
if(!d[v] && w > flow) { // 可走
d[v] = d[u] + 1;
q . push(v);
if(v == t) return 1;
}
}
}
return 0;
}
ll dfs(ll u , ll cpflow) {
if(u == t) return cpflow;
ll outflow = 0;
for(ll i = gg[u] ; i != -1 && outflow <= cpflow; i = e[i] . nxt) {
gg[u] = i;
ll v = e[i] . v , w = e[i] . w , flow = e[i] . flow;
if(d[v] == d[u] + 1 && w > flow) {
ll tmpdfs = dfs(v , min(cpflow - outflow , w - flow));
e[i] . flow += tmpdfs;
e[i ^ 1] . flow -= tmpdfs;
outflow += tmpdfs;
}
}
return outflow;
}
ll dinic() {
ll ans = 0;
while(bfs()) ans += dfs(s , INF);
return ans;
}
bool check(ll mid) {
s = 0 , t = n + 1;
memset(head , -1 , sizeof(head));
cnt = 0;
int mx = 0;
for(int i = 1; i <= n; i++) {
if(l[i] <= mid && c[i] == 1 && p[i] > p[mx]) mx = i;
}
int sum = 0;
for(int i = 1; i <= n; i++) {
if(l[i] <= mid) {
if(c[i] == 1 && i != mx) continue;
sum += p[i];
if(c[i] % 2) {
Link(s , i , p[i]);
for(int j = 1; j <= n; j++) {
if(l[j] <= mid && !notp[c[i] + c[j]] && c[j] % 2 == 0) {
Link(i , j , INF);
}
}
}
else Link(i , t , p[i]);
}
}
return sum - dinic() < k;
}
int main() {
inp(n , k);
notp[1] = 1;
for(int i = 2; i <= 200000; i++) {
// cout << notp[i] << " ";
if(!notp[i]) {
for(int j = i + i; j <= 200000; j += i) notp[j] = true;
}
}
for(int i = 1; i <= n; i++) {
inp(p[i] , c[i] , l[i]);
}
int l = 1 , r = n + 1 , ans = -1;
while(l < r) {
int md = (l + r) >> 1;
if(check(md)) l = md + 1;
else r = md;
}
outp(l > n ? -1 : l);
return 0;
}