云玩家拯救计划

这里列出了每天的题单
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;
}

猜你喜欢

转载自www.cnblogs.com/LiM-817/p/10332482.html