二分图匈牙利也可以
判断必须点就看能不能通过偶数长度的增广路翻过去
代码:
(最后一个点4s多才行,,,卡不过算了)
开始边数写少了RE,应该是4*N*N
M-R随手开了一堆int?都要是long long
// luogu-judger-enable-o2 #include<bits/stdc++.h> #define il inline #define reg register int #define numb (ch^'0') using namespace std; typedef long long ll; il void rd(int &x){ char ch;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=100+5; ll a[N][N]; int co[N*N]; int in[N*N]; int n,m; struct node{ int nxt,to; }e[8*N*N]; int hd[N*N],cnt; int num(int x,int y){ return (x-1)*m+y; } void add(int x,int y){ // cout<<" ahahhaa "<<endl; e[++cnt].nxt=hd[x]; e[cnt].to=y; hd[x]=cnt; } int to[N*N]; int vis[N*N]; bool dfs(int x,int id){ // cout<<" x "<<x<<" id "<<id<<endl; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; // cout<<" yy "<<y<<" vis "<<vis[y]<<endl; if(vis[y]==id) continue; vis[y]=id; if(!to[y]||dfs(to[y],id)){ to[y]=x; in[x]=1; to[x]=y; in[y]=1; return true; } } return false; } bool fin(int x,int id,int pos){ if(vis[x]==id) return false; vis[x]=id; if(pos==0){ if(!to[x]) return true; return fin(to[x],id,pos^1); } for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; if(y!=to[x]){ if(fin(y,id,pos^1)) return true; } } return false; } ll p[10]={2,3,7,61,24251}; ll add(ll x,ll y,ll p){ return x+y>=p?x+y-p:x+y; } ll qk(ll x,ll y,ll p){ ll ret=0; while(y){ if(y&1) ret=add(ret,x,p); x=add(x,x,p); y>>=1; } return ret; } ll qm(ll x,ll y,ll p){ ll ret=1; while(y){ if(y&1) ret=qk(ret,x,p); x=qk(x,x,p); y>>=1; } return ret; } bool che(ll x,ll d){ int s=0; ll lp=x-1; while(!(lp&1)){ ++s;lp>>=1; } ll now=qm(d,lp,x); if(now==1||now==x-1) return true; for(reg i=0;i<s;++i){ ll tmp=qk(now,now,x); if(tmp==1&&(now!=1&&now!=x-1)) return false; now=tmp; } if(now!=1) return false; return true; } bool M_R(ll x){ // cout<<" xx "<<x<<endl; if(x==0) return true; if(x==1) return true; if(x==46856248255981ll) return false; if(x==2||x==3||x==7||x==11||x==13||x==17||x==23||x==29||x==31||x==61||x==24251) return true; for(reg i=0;i<5;++i){ if(x%p[i]==0) return false; if(!che(x,p[i])) return false; } // cout<<" ok "<<endl; return true; } int mem[N*N],nb; int main(){ // cout<<" M_R "<<M_R(1557403521852231)<<endl; rd(n);rd(m); // cout<<" 2333 "<<endl; for(reg i=1;i<=n;++i){ for(reg j=1;j<=m;++j){ scanf("%lld",&a[i][j]); co[num(i,j)]=(i+j)%2; } } // return 0; for(reg i=1;i<=n;++i){ for(reg j=1;j<=m;++j){ if(a[i][j]==-1) continue; if(j!=m){ if(a[i][j+1]!=-1){ if(M_R(a[i][j]+a[i][j+1])==0){ add(num(i,j),num(i,j+1)); add(num(i,j+1),num(i,j)); } } } if(i!=n){ if(a[i+1][j]!=-1){ if(M_R(a[i][j]+a[i+1][j])==0){ add(num(i,j),num(i+1,j)); add(num(i+1,j),num(i,j)); // cout<<num(i,j)<<" "<<num(i+1,j)<<endl; } } } } } // cout<<" after build "<<endl; int tot=0; int le=0,ri=0; for(reg i=1;i<=n;++i){ for(reg j=1;j<=m;++j){ if(co[num(i,j)]==0&&a[i][j]!=-1){ ++le; tot+=dfs(num(i,j),num(i,j)); }else if(a[i][j]!=-1) ++ri; } } // cout<<" le ri "<<le<<" "<<ri<<" tot "<<tot<<endl; if(le==ri&&tot==le){ puts("0");return 0; } memset(vis,0,sizeof vis); for(reg i=1;i<=n;++i){ for(reg j=1;j<=m;++j){ if(a[i][j]!=-1){ if(!in[num(i,j)]||fin(to[num(i,j)],num(i,j),1)){ mem[++nb]=num(i,j); } } } } sort(mem+1,mem+nb+1); printf("%d ",nb); for(reg i=1;i<=nb;++i){ printf("%d %d ",(mem[i]-1)/m+1,mem[i]-((mem[i]-1)/m)*m); } return 0; } } signed main(){ // freopen("data3618.in","r",stdin); // freopen("data3618.out","w",stdout); Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/2/2 20:45:23 */
这个题的二分图匹配思想还是很巧妙
从最大匹配来考虑,便于决策