fzyzojP3618 -- [校内训练-互测20180412]士兵的游戏

二分图匈牙利也可以

判断必须点就看能不能通过偶数长度的增广路翻过去

代码:

(最后一个点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\n",nb);
    for(reg i=1;i<=nb;++i){
        printf("%d %d\n",(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
*/

 

这个题的二分图匹配思想还是很巧妙

从最大匹配来考虑,便于决策

 

posted @ 2019-02-02 23:30  *Miracle*  阅读(215)  评论(0编辑  收藏  举报