• 再探容斥好题——ROOK


    这个时候考过:安师大附中集训 Day2

    当时看shadowice1984的做法,但是没有亲自写,,,

    雅礼集训考试的时候鼓捣半天,被卡常到80pts,要跑9s

    卡不动。

    正解实际是:

    3重容斥

    1.随便选-一个对角线空+两个对角线空

    2.2^m枚举每一个位置放不放

    3.对角线空——若干个位置不空,再容斥

    A.一个对角线,枚举i个放在对角线上,C(*,i)组合数,剩下的方案数是(n-sz-i)!

    B.两个对角线,按圈DP,f[i][j]i圈,选了j个在对角线上方案数。枚举四个角放一个、对角放两个,都不放7种情况。

    常数很小。

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    namespace Modulo{
    const int mod=10007;
    il int ad(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    il int sub(int x,int y){return ad(x,mod-y);}
    il int mul(int x,int y){return (ll)x*y%mod;}
    il void inc(int &x,int y){x=ad(x,y);}
    il void inc2(int &x,int y){x=mul(x,y);}
    il int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
    template<class ...Args>il int ad(const int a,const int b,const Args &...args) {return ad(ad(a,b),args...);}
    template<class ...Args>il int mul(const int a,const int b,const Args &...args) {return mul(mul(a,b),args...);}
    }
    using namespace Modulo;
    namespace Miracle{
    const int N=104;
    const int M=12;
    int n,m;
    int X[M],Y[M];
    int hk[N],lk[N];
    int f[N][N];
    int c[N][N];
    int jie[N],inv[N];
    int C(int n,int m){
        if(n<0||m<0||n<m) return 0;
        return c[n][m];
    }
    int ans,two,one1,one2;
    int dp1(int sz){
        int lim=n;
        for(reg i=1;i<=n;++i){
            lim-=(hk[i]|lk[i]);
        }
        int ret=0;
        for(reg i=0;i<=lim;++i){
            inc(ret,mul(C(lim,i),jie[n-sz-i],i&1?mod-1:1));
        }
        return ret;
    }
    int dp2(int sz){
        int ret=0;
        int lim=n;
        for(reg i=1;i<=n;++i){
            lim-=(hk[i]|lk[n-i+1]);
        }
        for(reg i=0;i<=lim;++i){
            inc(ret,mul(C(lim,i),jie[n-sz-i],i&1?mod-1:1));
        }
        return ret;
    }
    int dp3(int sz){
        memset(f,0,sizeof f);
    
    //    cout<<"dp3----------- "<<sz<<endl;
    //    prt(hk,1,n);
    //    prt(lk,1,n);
        
        
        int U,D,L,R;
        int up=(n)/2;
        int lim=n-sz;
        if(n&1){
            U=D=L=R=(n+1)/2;
            f[0][0]=1;
            f[0][1]=(lk[L]==0&&hk[U]==0);
            --U;--L;++R;++D;
        }else{
            U=L=(n/2);D=R=(n/2)+1;
            f[0][0]=1;
        }
        for(reg i=0;i<up;++i){
            int o=min(2*i+(n&1),lim);
            for(reg j=0;j<=o;++j){
                if(f[i][j]){
                    int v=f[i][j];
                    inc(f[i+1][j],v);
    //                if(lk[R]+hk[U]==0)inc(f[i+1][j+1],v);
    //                if(lk[R]+hk[D]==0)inc(f[i+1][j+1],v);
    //                if(lk[L]+hk[U]==0)inc(f[i+1][j+1],v);
    //                if(lk[L]+hk[D]==0)
                    inc(f[i+1][j+1],mul((lk[R]+hk[U]==0)+(lk[R]+hk[D]==0)+(lk[L]+hk[U]==0)+(lk[L]+hk[D]==0),v));
                    
                    if(lk[R]+hk[U]==0&&lk[L]+hk[D]==0)inc(f[i+1][j+2],v);
                    if(lk[R]+hk[D]==0&&lk[L]+hk[U]==0)inc(f[i+1][j+2],v);
                }
            }
            --U;--L;++R;++D;
        }
        int ret=0;
        for(reg j=0;j<=lim;++j){
            inc(ret,mul(f[up][j],jie[n-sz-j],j&1?mod-1:1));
        }
    //    cout<<" ret "<<ret<<endl;
        return ret;
    }
    int dp4(int sz){
        return jie[n-sz];
    }
    void clear(){
        memset(f,0,sizeof f);
        memset(X,0,sizeof X);
        memset(Y,0,sizeof Y);
        ans=0;
        one1=0;one2=0;two=0;
    }
    int main(){
        
        int t;    
        rd(t);
        c[0][0]=1;
        n=102;
        for(reg i=1;i<=n;++i){
            c[i][0]=1;
            for(reg j=1;j<=n;++j){
                c[i][j]=ad(c[i-1][j],c[i-1][j-1]);
            }
        }
        jie[0]=1;
        for(reg i=1;i<=n;++i) jie[i]=mul(jie[i-1],i);
        
        while(t--){
            clear();
            rd(n);rd(m);
            for(reg i=1;i<=m;++i){
                rd(X[i]);rd(Y[i]);
                ++X[i];++Y[i];
            }
    //        ans=1;
    //        for(reg i=1;i<=n;++i) inc2(ans,i);
            ans=0;
            
            
            for(reg s=0;s<(1<<m);++s){
                memset(hk,0,sizeof hk);
                memset(lk,0,sizeof lk);
                int sz=__builtin_popcount(s);
                int c=(sz&1)?mod-1:1;
                bool fl1=true,fl2=true,fl=true;
                for(reg i=1;i<=m;++i){
                    if((s>>(i-1))&1){
                        if(X[i]==Y[i]) fl1=false;
                        if(X[i]+Y[i]==n+1) fl2=false;
                        if(hk[X[i]]) fl=false;
                        ++hk[X[i]];
                        if(lk[Y[i]]) fl=false;
                        ++lk[Y[i]];
                    }
                }
    //            cout<<" s "<<s<<" "<<fl1<<" "<<fl2<<" "<<fl<<endl;
                if(fl&&fl1){
                    inc(one1,mul(c,dp1(sz)));
                }
                if(fl&&fl2){
                    inc(one2,mul(c,dp2(sz)));
                }
                if(fl&&fl1&&fl2){
                    inc(two,mul(c,dp3(sz)));
                }
                if(fl){
                    inc(ans,mul(c,dp4(sz)));
                }
            }
    //        cout<<" one1 "<<one1<<endl;
    //        cout<<" one2 "<<one2<<endl;
    //        cout<<" two "<<two<<endl;
            inc(ans,ad(mod-one1,mod-one2,two));
    //        cout<<ans<<endl;l
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    }
    signed main(){
    //    freopen("rook.in","r",stdin);
    //    freopen("rook.out","w",stdout);
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */

    疯狂容斥

    对角线至少选择一个这种很麻烦。必须考虑有没有选择。

    格子都不能选很麻烦。要考虑给后面预留,只能状压

    对角线>=1——>都是0

    都是0——>有一些放了

    格子都不能选——>一些可以选

    以及按圈DP

    对称,方便同时处理可能产生矛盾的情况,避免状压。

  • 相关阅读:
    网站学习网站
    ajax利用json进行服务器与客户端的通信
    Json 数据
    Servlet 编程 请求的转发
    Servlet 编程 简单流程处理(重定向)
    Servlet 编程 http请求类型
    myeclipse10 .jsp将表单提交给.java(form网页与后台通信初识)
    myeclipse10 将一个java工程合并到web工程
    myeclipse 第一个web project
    JAVA字符串转日期或日期转字
  • 原文地址:https://www.cnblogs.com/Miracevin/p/11104740.html
Copyright © 2020-2023  润新知