zoukankan      html  css  js  c++  java
  • BZOJ 1072: [SCOI2007]排列perm [DP 状压 排列组合]

    题意:给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0)

    100%的数据满足:s的长度不超过10, 1<=d<=1000, 1<=T<=15


    看到整除应该往余数方面想

    $f[s][i]$表示当前已经选择的数的集合为$s$,余数为$i$的方案数

    枚举下一个数字,用更新的写法转移

    注意是有重复元素的排列!除上个阶乘

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=1005,S=(1<<10)+5;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,d,a[12],c[12];
    char s[20];
    int f[S][N];
    int main(){
        //freopen("in","r",stdin);
        int T=read();
        while(T--){
            scanf("%s",s);d=read();
            n=strlen(s);
            memset(c,0,sizeof(c));
            for(int i=0;i<n;i++) a[i]=s[i]-'0',c[a[i]]++;
            int All=1<<n;
             
            for(int s=0;s<All;s++) for(int i=0;i<d;i++) f[s][i]=0;
            f[0][0]=1;
            for(int s=0;s<All;s++)
                for(int i=0;i<d;i++) if(f[s][i]){
                    for(int j=0;j<n;j++) if( (s&(1<<j))==0 ) 
                        f[s|(1<<j)][(i*10+a[j])%d]+=f[s][i];
                }
     
            int ans=f[All-1][0];
            for(int i=0;i<=9;i++) while(c[i]) ans/=c[i],c[i]--;
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    ESXi创建磁盘命令
    TNS-12518,TNS-12536,TNS-00506,Linux Error: 11: Resource temporarily unavailable
    监听的instance status blocked分析
    Oracle 用户、对象权限、系统权限
    MIME详解
    11g等待事件之library cache: mutex X
    Latch Free
    PowerDesigner小技巧
    yum本地源配置
    内核参数SEMMSL SEMMNS SEMOPM SEMMNI参数的设置
  • 原文地址:https://www.cnblogs.com/candy99/p/6512667.html
Copyright © 2011-2022 走看看