用两个状态S,K
S中第i位为1,说明出现了奇数次,为0说明出现偶数次。
K中第i位为1,说明数字i出现过,为0说明没出现。
复杂度10的7次方。。。120ms跑过。。。
正解应该是用三进制把两个状态合并。
我的代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef unsigned long long LL;
LL a,b,dp[25][1<<10][1<<10];
int bit[25],top;
bool jud(int s,int k){
for(int i=0;i<10;i++){
if(k >> i & 1){
if((i & 1) && (s >> i & 1)) return false;
if(!(i & 1) && !(s >> i & 1)) return false;
}
}
return true;
}
LL dfs(int i,int s,int k,bool e,bool z){
//printf("%d %d %d\n",i,s,k);
if(i == -1) return k && jud(s,k) ? 1 : 0;
if(!e && dp[i][s][k] != -1) return dp[i][s][k];
LL res = 0;
int d , u = e ? bit[i] : 9;
for(d = 0;d <= u ;d++)
res += dfs(i-1,z&&(d==0) ? 0 : (s^(1<<d)),z&&(d==0) ? 0 : (k|(1<<d)),e&&(d==u),z&&(d==0));
return e ? res : dp[i][s][k] = res;
}
LL solve(LL n){
//printf("!!!!\n");
top = 0;
for(;n;n/=10) bit[top++] = (int)(n%10);
return dfs(top-1,0,0,1,1);
}
int main(){
int cas;
scanf("%d",&cas);
memset(dp,-1,sizeof(dp));
while(cas--){
scanf("%llu%llu",&a,&b);
printf("%llu\n",solve(b) - solve(a-1));
}
return 0;
}