诶写了几天终于写过去了
看了网上无数的模板,发现都不好用,最后还是用了自己的办法写出来
细节多而且复杂
状态压缩DP,F[mask]表示mask状态下的答案方案数,G[mask]表示取一个状态为mask的数的方案数
F[S]=∑(G[p]∗F[S异或p])
其中p包含了lowbit(S)
至于G[]数组怎么求,那就是另外一个数位DP了
dp[i][j][mask]表示第i位,这位上的数为j,且已经选择出来的数集合为mask的方案数
dp完了再搜索一遍把所有状态抠出来就可以了
#include <iostream>
#include <cstdio>
#include <cstring>
#define N 4100
#define mod 1000000007 //1e9+7
using namespace std;
typedef long long LL;
inline int lowbit(int x){return x & (-x);}; //集合中编号最小的元素
inline void ad(LL &a,LL b) { a = (a + b) % mod; }
LL F[N],G[N],dp[11][11][N];
int num[11],n,top;
void predp() {
memset(dp,0,sizeof(dp));
for (int i=0;i<=9;i++) dp[1][i][1<<i] = 1LL;
for (int i=2;i<=n;i++)
for (int j=0;j<=9;j++)
for (int k=0;k<=9;k++)
for (int S=1;S<=top;S++) if ( ((1<<k)&S) && ((1<<j)&S) ) {
ad( dp[i][j][S] , dp[i-1][k][S] );
ad( dp[i][j][S] , dp[i-1][k][S^(1<<j)] );
}
return ;
}
LL dfs(int x,int mask) {
LL r = 0LL;
if (x == 0) return 0;
for (int i=(x==n?1:0);i<num[x];i++) ad( r , dp[x][i][mask] );
if (mask&(1<<num[x])) {
ad(r , dfs(x-1,mask^(1<<num[x])));
ad(r , dfs(x-1,mask ));
}
return r;
}
LL get(int mask) {
LL r = 0LL;
for (int i=1;i<n;i++)
for (int j=1;j<=9;j++) ad(r , dp[i][j][mask]);
ad(r,dfs(n,mask));
return r;
}
void solve() {
memset(F,0,sizeof(F));
memset(G,0,sizeof(G));
LL ans = 0LL;
top = (1<<12)-1;
scanf("%d",&n); int l = 0; n++;
while (n) { num[++l] = n%10; n /= 10; }
n = l;
predp();
for (int i=1;i<=top;i++) F[i] = G[i] = get(i);
for (int i=1;i<=top;i++) {
int t = lowbit(i);
for (int j=(i^t);j>0;j=(j-1)&(i^t)) ad(F[i] , F[j] * G[i^j]);
//for (int j=(i^t);j;j=(j-1)&(i^t)) ad(F[i] , F[j]*G[i^j]);
}
for (int i=1;i<=top;i++) {
ad(ans , F[i]);
}
printf("%d\n",(int)ans);
}
int main()
{
int T = 0; scanf("%d",&T);
for (int _=1;_<=T;_++) { printf("Case %d: ",_); solve(); }
return 0;
}