BZOJ 1072: [SCOI2007]排列perm

状态压缩Dp

f[i][j],i为状态,j为余数

i可以用二进制数表示状态

这样的话状态转移就很简单了

但最后要用排列组合算一下重复排序。。。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 using namespace std;
  6 int i,j,k,n,m,t,a,b,c,d;
  7 int p[11]={};
  8 int l[11]={};
  9 int f[1024][1001]={};
 10 bool r[1024][1001]={};
 11 bool e[11]={};
 12 char s;
 13 void er(int x)
 14 {
 15     int i,j,k;
 16     k=-1;
 17     while(x!=0)
 18     {
 19         k++;
 20         e[k]=x%2;
 21         x=x/2;
 22     }
 23 }
 24 int pow(int x,int y)
 25 {
 26     int i,j;
 27     j=1;
 28     for(i=1;i<=y;i++)
 29     {
 30            j=j*x;
 31     }
 32     return j;
 33 } 
 34 int aa(int x)
 35 {
 36     int i,j,a,b,c;
 37     c=1;
 38     for(i=1;i<=x;i++)
 39     {
 40          c=c*i;
 41     }
 42     return c;
 43 }                                 
 44 int main()
 45 {
 46     scanf("%d",&t);
 47     for(n=1;n<=t;n++)
 48     {
 49         memset(p,0,sizeof(p));
 50         memset(l,0,sizeof(l)); 
 51         memset(f,0,sizeof(f)); 
 52         memset(r,0,sizeof(r)); 
 53         memset(e,0,sizeof(e));              
 54         cin>>s;
 55         c=-1;
 56         while(int(s)!=32)
 57         {          
 58               p[int(s)-48]++;
 59               c++;
 60               l[c]=int(s)-48;
 61               scanf("%c",&s);
 62         }
 63         scanf("%d",&d); 
 64         r[0][0]=1;
 65         f[0][0]=1;                    
 66         for(i=0;i<=1023;i++)
 67         {
 68                 memset(e,0,sizeof(e));     
 69                 er(i);
 70                 a=0;
 71                 for(j=0;j<=c;j++)
 72                 {
 73                       if(e[j]==0)
 74                       {
 75                             a=1;
 76                       }
 77                 }
 78                 if(a==0)
 79                 {
 80                        a=i; 
 81                        break;
 82                 }                   
 83                 for(j=0;j<=d-1;j++)
 84                 {
 85                     if(r[i][j]==1)
 86                     {               
 87                       for(k=0;k<=c;k++)
 88                       {
 89                              if(e[k]==0)
 90                              {
 91                                   f[i+pow(2,k)][(j*10+l[k])%d]+=f[i][j];
 92                                   r[i+pow(2,k)][(j*10+l[k])%d]=1;
 93                              }
 94                       }
 95                     }
 96                 }      
 97         }
 98          for(i=0;i<=9;i++)
 99                 {
100                       f[a][0]=f[a][0]/aa(p[i]);
101                 }
102                 cout<<f[a][0]<<endl;    
103     }                                          
104     return 0;
105 }
View Code

 

转载于:https://www.cnblogs.com/wyc91543/p/3613164.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值