1. 程式人生 > >BZOJ2744 [HEOI2012]朋友圈

BZOJ2744 [HEOI2012]朋友圈

傳送門

題解: 顯然A國模2的餘數相同的沒有邊,即A國的朋友關係是二分圖。那麼A國的朋友圈最多2個人。(否則如果有3個人,就有2個人模2的餘數相同,做不了朋友)。 B國稍微複雜,因為它本身並不是二分圖。但它的補圖是二分圖,所以可以在補圖上跑一發最大獨立集,求法為總點數-最大匹配數。 然後列舉A中的點,對於B中和列舉的點都連線的點跑二分圖匹配即可。 然後這道題需要注意討論版:

leoly:對於B類點:偶數點連向奇數點,時間20000+ms;奇數點連向偶數點,時間2000+ms kac:注意這題實際資料中 只有一組資料 而且沒有輸入t

話說我一部分memset一部分時間戳到底是要幹什麼,反正364ms過了

程式碼:

#include<cstdio>
#include<cstring>
#define maxb 3005
#define maxa 205
#define maxm 9000005
#define max(a,b) ((a)>(b)?(a):(b))
int na,nb,m,mx[maxb],my[maxb],a[maxa],b[maxb],cnt,ok[maxb],vis[maxb],ans,mat;
bool G[maxa][maxb];
struct node { int v; node *nxt; } edge[maxm],*head[maxb],*ncnt;
void
addedge(int u,int v) { ncnt++; ncnt->v=v,ncnt->nxt=head[u]; head[u]=ncnt; } int dfs(int u) { for(node *p=head[u];p;p=p->nxt) { int v=p->v; if(vis[v]==cnt||ok[v]!=cnt) continue; vis[v]=cnt; if(!my[v]||dfs(my[v])) { mx[u]=v,my[v]=u; return
1; } } return 0; } int Get(int x) { int cnt=0; for(;x;x-=x&(-x)) cnt++; return cnt; } int main() { scanf("%d%d%d",&na,&nb,&m); ncnt=&edge[0]; for(int i=1;i<=na;i++) scanf("%d",&a[i]); for(int i=1;i<=nb;i++) scanf("%d",&b[i]); for(int i=1;i<=m;i++) { int u,v; scanf("%d%d",&u,&v); G[u][v]=true; } for(int i=1;i<=nb;i++) for(int j=i+1;j<=nb;j++) if((b[i]+b[j])%2&&Get(b[i]|b[j])%2==0) { if(b[i]%2) addedge(i,j); else addedge(j,i); } cnt++; for(int i=1;i<=nb;i++) ok[i]=cnt; for(int i=1;i<=nb;i++) if(!mx[i]&&b[i]%2) mat+=dfs(i); ans=nb-mat; for(int i=1;i<=na;i++) { memset(mx,0,sizeof(mx)); memset(my,0,sizeof(my)); cnt++,mat=0; int cb=0; for(int j=1;j<=nb;j++) if(G[i][j]) ok[j]=cnt,cb++; for(int j=1;j<=nb;j++) if(ok[j]==cnt&&!mx[j]&&b[j]%2) mat+=dfs(j); ans=max(ans,1+cb-mat); for(int j=i+1;j<=na;j++) if((a[i]+a[j])%2) { cnt++,mat=cb=0; memset(mx,0,sizeof(mx)); memset(my,0,sizeof(my)); for(int k=1;k<=nb;k++) if(G[i][k]&&G[j][k]) ok[k]=cnt,cb++; for(int k=1;k<=nb;k++) if(ok[k]==cnt&&!mx[k]&&b[k]%2) mat+=dfs(k); ans=max(ans,2+cb-mat); } } printf("%d\n",ans); }