2018-2019 ACM-ICPC, Asia Nanjing Regional Contest

https://codeforces.ml/gym/101981

A 博弈 (相关专题待补)

博弈的精髓在于对称
此处的对称有两种,
一 ,后手让局面永远保持某种状态 如 min博弈中的 ( m + 1 ) (m + 1) (m+1)状态
二 ,在多组数据博弈当中,两堆相同的元素,可以进行模仿,从而达到必胜(和SG中的异或有类似

J 素数分隔区间并计算贡献次数

存在一个比较优秀的时间复杂度证明,首先对于一个数,只需要筛到其剩余部分的根号即可判断剩余部分是 质数
这里有一个很妙的做法,就是加上isprime[i] 不仅可以 化简时间复杂度到根号,同时可以 把一些奇奇怪怪的有大素数因子的数快速筛掉

I 网络流,两边二分匹配

或者多连接一个次源点,让源点和次源地的流量为k,次源点同样连接每一个n
有些细节需要注意now和head,每次只会Dfs查询Bfs已经跟新过的范围,head的初始值只与cnt有关,让cnt从二开始,初始化为1,head的初始值为0

明显匈牙利更好一点,而且匈牙利算法更浪漫一些QAQ

#include <bits/stdc++.h>
using namespace std;
const int Mn = 2e6 + 5;
int head[Mn],now[Mn];
struct {
    int to,flow,nxt;
}Edge[Mn << 1];
int cnt = 1;
inline void Adde(int a,int b,int c){
    Edge[++cnt].nxt = head[a];
    Edge[cnt].to = b;
    Edge[cnt].flow = c;
    head[a] = cnt;
    Edge[++cnt].nxt = head[b];
    Edge[cnt].to = a;
    Edge[cnt].flow = 0;
    head[b] = cnt;
}
int s,e;
const int inf = 0x3f3f3f3f;
int n,m,k;
int dis[Mn];
bool Bfs(){
    int u,v;
    memset(dis,inf,sizeof(dis));
    dis[s] = 0;
    queue <int> q;
    q.push(s);
    while(!q.empty()){
        u = q.front();
        q.pop();
        now[u] = head[u];
        for(int p = head[u];p;p = Edge[p].nxt){
            v = Edge[p].to;
            if(dis[v] != inf || !Edge[p].flow) continue;
            dis[v] = dis[u] + 1;
            if(v == e) return 1;
            q.push(v);
        }
    } return 0;
}
int Dfs(int u,int limit){
    if(u == e || !limit) return limit;
    int flow = 0,f,v;
    for(int p = now[u];p;p = Edge[p].nxt){
        v = Edge[p].to;
        now[u] = p;
        if(dis[v] != dis[u] + 1 || !Edge[p].flow) continue;
        f = Dfs(v,min(limit,Edge[p].flow));
        Edge[p].flow -= f;
        Edge[p ^ 1].flow += f;
        flow += f;
        limit -=f;
        if(limit == 0) return flow;
    }return flow;
}
int ans = 0;
inline void Dininc(){
    while(Bfs()) //puts("xxxx");
        ans += Dfs(s,inf);
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    int K= n + m + 2;
    s = 0,e = n + m + 1;
    for(int i = 1;i <= n;i ++){
        Adde(s,i,1);
        Adde(K,i,1);
        int x;scanf("%d",&x);
        for(int j = 1;j <= x;j ++){
            int v;scanf("%d",&v);
            v += n;
            Adde(i,v,1);
        }
    }
    for(int i = 1;i <= m;i ++){
        Adde(i + n,e,1);
    }
    Adde(s,K,k);
    Dininc();
    printf("%d",ans);
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
const int Mn = 1e3 + 5;
vector <int> son[Mn];
int mate[Mn],vis[Mn];
bool forget(int a,int k){
    for(int v : son[a]){
        if(vis[v] == k) continue;
        vis[v] = k;
        if(mate[v] == 0 || forget(mate[v],k) ){
            mate[v] = a;
            return 1;
        }
    }
    return 0;
}
int main()
{
    int n,m,k;
    int ans =0;
    scanf("%d%d%d",&n,&m,&k);
    int v;
    int x;
    for(int i = 1;i <= n;i ++){
        scanf("%d",&x);
        for(int j = 1;j <= x;j ++){
            scanf("%d",&v);
            v += n;
            son[i].push_back(v);
        }
    }
    int res = 0;
    int pos = 0;
    for(int i = 1;i <= n;i ++){
        ans += forget(i,++pos);
    }
    res = ans;
    for(int i = 1;i <= n;i ++){
        ans += forget(i,++pos);
    }
    //printf("%d %d %d\n",ans,res);
    ans = min(ans,res + k);
    printf("%d\n",ans);
    return 0;
}

D 退火

G找规律 多项式的系数

以上两个大坑QAQ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值