zoukankan      html  css  js  c++  java
  • bzoj1072: [SCOI2007]排列perm

    思路:状压dp,f[i][j]表示新的排列的状态为i(也就是新的排列已经选了哪些数),然后模d的余数为j的方案数。

    但考虑到可能有些数会出现多次,假设一个数x出现了cnt[x]次,那么对于一个可行的答案,显然也包含cnt[x]个x,那么这样的答案就会被计算多次,因为如果状态i先加入第一个x再加入第二个x和状态i先加入第二个x再加入第一个x显然是算作两种不同的方案,但其实他们是一样的,但对于某一个确定的合法的答案,x的位置不会变,因此如果重复的情况只可能是该答案中所有的x在互换,这种互换会被多次统计但答案其实只有一个,可以发现这种互换的情况数有cnt[x]!种(本质上就是一个长为cnt[x]的排列的情况数),然后答案除以cnt[x]!就可以完成去重了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    #define maxn 1<<11
     
    int cases,p;
    int cnt[15],f[maxn][maxn];
    char s[15];
     
    int main(){
        scanf("%d",&cases);
        while (cases--){
            scanf("%s%d",s,&p);int n=strlen(s);
            memset(f,0,sizeof(f)),f[0][0]=1,memset(cnt,0,sizeof(cnt));
            for (int i=0;i<n;i++) cnt[s[i]-'0']++;
            for (int i=0;i<(1<<n);i++)
                for (int m=0;m<p;m++)
                    for (int j=0;j<n;j++)
                        if (!(i&(1<<j))) f[i|(1<<j)][(m*10+s[j]-'0')%p]+=f[i][m];
            int ans=f[(1<<n)-1][0];
            for (int i=0;i<=9;i++)
                for (int j=2;j<=cnt[i];j++)
                    ans/=j;
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【JavaScript】JavaScript 思维导图
    python logging 模块
    推荐系统
    【Linux】国内镜像汇总
    python 小游戏练手
    Python3 拼图小游戏
    python cls self 讲解
    Python-插件化开发
    Python-并发和线程
    git命令的使用
  • 原文地址:https://www.cnblogs.com/DUXT/p/5990741.html
Copyright © 2011-2022 走看看