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