• BZOJ 1004 Cards(Burnside引理+DP)


    因为有着色数的限制,故使用Burnside引理。

    添加一个元置换(1,2,,,n)形成m+1种置换,对于每个置换求出循环节的个数,

    每个循环节的长度。

    则ans=sigma(f(i))/(m+1) %p  (1<=i<=m+1).

    其中f(i)是第i种置换下的不动点个数。

    可以用dp来求出f(i), 设第i个置换的循环节个数为T, 令dp[i][j][k]表示前i个循环节中使用了j个红色,k个蓝色的不动点个数。进行一次n^3的DP即可。

    最后m+1模p意义下的逆元不再叙述。

    # include <cstdio>
    # include <cstring>
    # include <cstdlib>
    # include <iostream>
    # include <vector>
    # include <queue>
    # include <stack>
    # include <map>
    # include <set>
    # include <cmath>
    # include <algorithm>
    using namespace std;
    # define lowbit(x) ((x)&(-x))
    # define pi acos(-1.0)
    # define eps 1e-3
    # define MOD 1000000007
    # define INF (LL)1<<60
    # define mem(a,b) memset(a,b,sizeof(a))
    # define FOR(i,a,n) for(int i=a; i<=n; ++i)
    # define FO(i,a,n) for(int i=a; i<n; ++i)
    # define bug puts("H");
    # define lch p<<1,l,mid
    # define rch p<<1|1,mid+1,r
    # define mp make_pair
    # define pb push_back
    typedef pair<int,int> PII;
    typedef vector<int> VI;
    # pragma comment(linker, "/STACK:1024000000,1024000000")
    typedef long long LL;
    int Scan() {
        int res=0, flag=0;
        char ch;
        if((ch=getchar())=='-') flag=1;
        else if(ch>='0'&&ch<='9') res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
        return flag?-res:res;
    }
    void Out(int a) {
        if(a<0) {putchar('-'); a=-a;}
        if(a>=10) Out(a/10);
        putchar(a%10+'0');
    }
    const int N=100005;
    //Code begin...
     
    struct Per{int a[65];}per[65];
    int dp[65][65][65], n, vis[65], num[65];
     
    int get_loop(int x)
    {
        int cnt=0;
        mem(vis,0); mem(num,0);
        FOR(i,1,n) {
            if (vis[i]) continue;
            ++cnt;
            int now=i;
            while (vis[now]==0) vis[now]=1, now=per[x].a[now], ++num[cnt];
        }
        return cnt;
    }
    int extend_gcd(int a, int b, int &x, int &y)
    {
        if (a==0&&b==0) return -1;
        if (b==0){x=1; y=0; return a;}
        int d=extend_gcd(b,a%b,y,x);
        y-=a/b*x;
        return d;
    }
    int mod_reverse(int a, int n)
    {
        int x, y, d=extend_gcd(a,n,x,y);
        if (d==1) return (x%n+n)%n;
        else return -1;
    }
    int main ()
    {
        int sr, sb, sg, m, p;
        LL ans=0;
        scanf("%d%d%d%d%d",&sr,&sb,&sg,&m,&p);
        n=sr+sb+sg;
        FOR(i,1,m) FOR(j,1,n) scanf("%d",&per[i].a[j]);
        FOR(j,1,n) per[m+1].a[j]=j;
        FOR(i,1,m+1) {
            int t=get_loop(i);
            mem(dp,0);
            dp[0][0][0]=1;
            int sum=0;
            for (int j=1; j<=t; ++j) FOR(k,0,sr) FOR(l,0,sb) {
                sum+=num[j];
                if (k+l>sum) continue;
                if (sum-k-l>=num[j]) dp[j][k][l]=dp[j-1][k][l];
                if (k>=num[j]) dp[j][k][l]=(dp[j][k][l]+dp[j-1][k-num[j]][l])%p;
                if (l>=num[j]) dp[j][k][l]=(dp[j][k][l]+dp[j-1][k][l-num[j]])%p;
            }
            ans=(ans+dp[t][sr][sb])%p;
        }
        ans=ans*mod_reverse(m+1,p)%p;
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    1004: 画图
    1002: 数字排序问题
    1003: 相邻数对问题
    1001: 图像旋转问题
    1000: 数塔
    springday05-go1
    springday04-go2
    springday04-go1
    springday03-go2
    Android—PopupWindow的简单使用
  • 原文地址:https://www.cnblogs.com/lishiyao/p/6479828.html
Copyright © 2020-2023  润新知