题目大意:
求[l,r]区间的平衡数的个数。
平衡数:所有数位中每一个奇数出现偶数次,每一个偶数出现奇数次。
题解:
定义flag为0表示未出现,1表示出现奇数次,2表示出现偶数次。
所以我们可以把0-9的所有数状压成一个10位的三进制数state,这个状态记录每个数的出现情况。
定义状态为dp[pos][state]表示枚举到pos位,状态为state。
每当枚举下一个数位时,更新枚举数位对状态的影响就行了。
最后返回时再判断是否符合条件就行了。
代码实现:
#pragma GCC optimize(2) #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <cstdio> #include <cstdlib> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #define PI atan(1.0) * 4 #define E 2.718281828 #define rp(i, s, t) for (register int i = (s); i <= (t); i++) #define RP(i, t, s) for (register int i = (t); i >= (s); i--) #define ll long long #define ull unsigned long long #define mst(a, b) memset(a, b, sizeof(a)) #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define pii pair<int, int> #define mp make_pair #define pb push_back #define debug printf("ac\n"); using namespace std; inline int read() { int a = 0, b = 1; char c = getchar(); while (c < '0' || c > '9') { if (c == '-') b = -1; c = getchar(); } while (c >= '0' && c <= '9') { a = (a << 3) + (a << 1) + c - '0'; c = getchar(); } return a * b; } int a[20],num; ll dp[20][60005]; int judge(int state){ int digit[20]; rp(i,0,9){ digit[i]=state%3; state/=3; } rp(i,0,9){ if(digit[i]!=0){ if(i%2==0&&digit[i]==2) return 0; if(i%2==1&&digit[i]==1) return 0; } } return 1; } int getnum(int x,int state){ int digit[20]; rp(i,0,9){ digit[i]=state%3; state/=3; } if(digit[x]==0) digit[x]=1; else digit[x]=3-digit[x]; int res=0; RP(i,9,0){ res*=3; res+=digit[i]; } return res; } ll dfs(int pos,int state,int lead,int limit){ if(pos==-1) return judge(state); if(!lead&&!limit&&dp[pos][state]!=-1) return dp[pos][state]; int up=limit?a[pos]:9; ll ans=0; rp(i,0,up) ans+=dfs(pos-1,(lead&&i==0)?0:getnum(i,state),lead&&i==0,limit&&i==a[pos]); if(!limit&&!lead) return dp[pos][state]=ans; return ans; } ll solve(ll x){ num=0; while(x) a[num++]=x%10,x/=10; return dfs(num-1,0,1,1); } int main(){ mst(dp,-1); int T=read(); ll l,r; while(T--){ scanf("%lld%lld",&l,&r); printf("%lld\n",solve(r)-solve(l-1)); } // printf("\n"); return 0; }
SPOJBALNUM——数位dp+状压
最新推荐文章于 2024-01-20 11:40:12 发布