您的位置:首页 > 其它

bzoj 1072 状压DP

2014-04-22 09:46 274 查看
  我们用w[i][j]来表示,i是一个二进制表示我们选取了s中的某些位,j表示这些位%d为j,w[i][j]则表示这样情况下的方案数,那么我们可以得到转移.w[i|(1<<k)][(j*10+s[k]-'0')%d]+=w[i][j]。

  假设s中有x个3,那么我们算出的状态中同样的数我们算了x!次,最后除掉就好了。

/**************************************************************
Problem: 1072
User: BLADEVIL
Language: C++
Result: Accepted
Time:476 ms
Memory:12680 kb
****************************************************************/

//By BLADEVIL
#include <cstdio>
#include <cstring>

using namespace std;

int d,cnt[11],w[3010][1010];
char s[11];

int main() {
int task; scanf("%d",&task);
while (task--) {
scanf("%s%d",s,&d); int len=strlen(s);
memset(cnt,0,sizeof cnt);
for (int i=0;i<len;i++) cnt[s[i]-'0']++;
for (int i=0;i<(1<<len);i++)
for (int j=0;j<d;j++) w[i][j]=0;
w[0][0]=1;
for (int i=0;i<(1<<len);i++)
for (int j=0;j<d;j++) if (w[i][j])
for (int k=0;k<len;k++) if (!(i&(1<<k)))
w[i|(1<<k)][(j*10+s[k]-'0')%d]+=w[i][j];
int ans=w[(1<<len)-1][0];
//printf("%d\n",ans);
for (int i=0;i<10;i++)
for (int j=1;j<=cnt[i];j++) {
ans/=j ;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: