看到诸位神牛的代码和Blog,我也来班门弄斧学一下 数位dp
向ftiasch 和 edward_mj (窃笑,师父们T_T)求了资料,得到一个好板子——BUPT 某神的Blog
HDU 2089 直接暴力就可以,不过还是老老实实地数位dp一把,基本是板子题目。
HDU 3555 同上的数位DP
UESTC 1307 前导0 建立状态原来还可以用11来代替啊。这样的话每次Quest dfs一次即可。
POJ 3252 f[pos][s][zero][one]
http://acm.hdu.edu.cn/showproblem.php?pid=4507
LL cnt[20][2][7][7] , dp[20][2][7][7] , dpsum[20][2][7][7]; LL ten[20]; LL num[20]; void init(){ ten[0] = 1; REP_1(i , 19) ten[i] = (ten[i - 1] * 10) % MOD; } LL dfscnt(int i, bool seven , int numbersum, int sum , bool e) { if (i==-1) return (seven || numbersum % 7 == 0 || sum % 7 == 0) ? 1 : 0; if (!e && ~cnt[i][seven][numbersum][sum]) return cnt[i][seven][numbersum][sum]; LL res = 0; int u = e?num[i]:9; for (int d = 0; d <= u; ++d) res = ( res + dfscnt(i-1, (seven || d == 7), (numbersum + d) % 7 , (sum * 10 + d) % 7 , e&&d==u)) % MOD; return e?res:cnt[i][seven][numbersum][sum]=res; } LL mul(LL x , LL y){ x %= MOD; y %= MOD; return (x * y) % MOD; } LL dfssum(int i , int seven , int numbersum , int sum , bool e){ if (i == -1) return 0; if (!e && ~dpsum[i][seven][numbersum][sum]) return dpsum[i][seven][numbersum][sum]; LL res = 0; int u = e ? num[i] : 9; for (int d = 0 ; d <= u ; ++d){ LL has = dfscnt(i-1, (seven || d == 7), (numbersum + d) % 7 , (sum * 10 + d) % 7 , e&&d==u); LL tmp = mul(d , ten[i]); tmp = mul(has , tmp); res = (res + dfssum(i-1, (seven || d == 7), (numbersum + d) % 7 , (sum * 10 + d) % 7 , e&&d==u)) % MOD; res = (res + tmp) % MOD; } return e ? res : dpsum[i][seven][numbersum][sum] = res ; } LL dfs(int i , int seven , int numbersum , int sum , bool e){ if (i == -1) return 0; if (!e && ~dp[i][seven][numbersum][sum]) return dp[i][seven][numbersum][sum]; LL res = 0; int u = e ? num[i] : 9; for (int d = 0 ; d <= u ; ++d){ LL has = dfscnt(i-1, (seven || d == 7), (numbersum + d) % 7 , (sum * 10 + d) % 7 , e&&d==u); LL sum1 = dfssum(i-1, (seven || d == 7), (numbersum + d) % 7 , (sum * 10 + d) % 7 , e&&d==u); LL tmp = mul(d , ten[i]); LL nownow = mul(tmp , tmp); LL hasnow = mul(nownow , has); nownow = mul(2 , mul(tmp , sum1)); res = (res + dfs(i-1, (seven || d == 7), (numbersum + d) % 7 , (sum * 10 + d) % 7 , e&&d==u)) % MOD; res = (res + hasnow) % MOD; res = (res + nownow) % MOD; } return e ? res : dp[i][seven][numbersum][sum] = res ; } LL l , r; LL gao(LL x){ LL a = x , b = x + 1 , c = 2 * x + 1; LL p = 2; if (a % p == 0) a /= p; else if (b % p == 0) b /= p; else if (c % p == 0) c /= p; p = 3; if (a % p == 0) a /= p; else if (b % p == 0) b /= p; else if (c % p == 0) c /= p; return mul(mul(a , b) , c); } LL getans(LL x){ if (x == 0) return 0; int s = 0; LL y = x; while(x){ num[s ++ ] = x % 10; x /= 10; } x = y; LL res = gao(x); res -= dfs(s - 1 , 0 , 0 , 0 , 1); res %= MOD; res += MOD; res %= MOD; return res; } void solve(){ RD(l , r); LL ans = getans(r) - getans(l - 1); ans %= MOD; ans += MOD; ans %= MOD; printf("%I64d\n" , ans); } int main(){ FLC(dp , -1); FLC(cnt , -1); FLC(dpsum , -1); init(); Rush solve(); }
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<vector> #include<map> #include<set> #include<queue> #include<string> #include<iostream> using namespace std; typedef long long LL; typedef double db; #define mp make_pair #define pb push_back const LL P = (int)1e9 + 7; LL f[20][9 * 20][7][2];//cnt LL sum1[20][9 * 20][7][2];// sum = 1次和 LL sum2[20][9 * 20][7][2];//sum = 2次和 LL ten[100]; void update(LL &a, LL b) { a = (a + b) % P ; if(a<0) a+=P; } LL MOD(LL a) { a %= P; return a <0 ? a + P : a; } /*debug*/ LL _f[20][9 * 20][7][2]; LL _sum1[20][9 * 20][7][2]; LL _sum2[20][9 * 20][7][2]; void _pre(){ _f[0][0][0][0]= 1; for(LL i = 1;i<=6;++i) { LL lo = 0, hi = ten[i]-1; for(LL v = lo; v <= hi; ++ v){ LL rem = v % 7, dsum = 0; LL k = v,msk = 0; while(k){ LL d = k%10; if(d == 7) msk = 1; dsum += d;k/=10; } _f[i][dsum][rem][msk]++; update(_sum1[i][dsum][rem][msk] , v); update(_sum2[i][dsum][rem][msk] , (LL)v*v%P); } } for(LL i = 0; i <= 6; ++ i) { LL sumlim = i * 9; for(LL sum = 0; sum <= sumlim; ++ sum) { for(LL modres = 0; modres < 7; ++ modres) { for(LL has7 = 0; has7 < 2; ++ has7) { if(_f[i][sum][modres][has7] != f[i][sum][modres][has7]) { cout << "error at f!" << endl; return; } if(_sum1[i][sum][modres][has7] != sum1[i][sum][modres][has7]) { cout << "error at s1!" << endl; cout << i <<" " << sum <<" " << modres << " " << has7 << endl; cout <<_sum1[i][sum][modres][has7] <<" "<<sum1[i][sum][modres][has7]<<endl; return; } if(_sum2[i][sum][modres][has7] != sum2[i][sum][modres][has7]) { cout << "error at s2!" << endl; cout <<_sum2[i][sum][modres][has7] <<" "<<sum2[i][sum][modres][has7]<<endl; return; } } } } } cout <<"ok"<<endl; } LL ten7[100]; void pre(){ f[0][0][0][0] = 1; ten[0] = 1; ten7[0]=1; for(LL i = 1; i <= 99; ++ i) ten[i]=ten[i-1] * 10%P; for(LL i = 1; i <= 99; ++ i) ten7[i]=ten7[i-1] * 10%7; for(LL i = 1; i <= 19; ++ i) { for(LL j = 0; j < 10; ++ j) { LL sumlim = (i-1) * 9; for(LL sum = 0; sum <= sumlim; ++ sum) { for(LL modres = 0; modres < 7; ++ modres) { for(LL has7 = 0; has7 < 2; ++ has7) { LL nbit = i, nsum = sum + j, nmod = (modres+ten7[i-1]*j%7)%7,nhas = has7 | (j == 7); if( nsum <= sumlim + 9) { update(f[nbit][nsum][nmod][nhas], f[i-1][sum][modres][has7]); } } } } } } // sum1 for(LL i = 1; i <= 19; ++ i) { for(LL j = 0; j < 10; ++ j) { LL sumlim = (i-1) * 9; for(LL sum = 0; sum <= sumlim; ++ sum) { for(LL modres = 0; modres < 7; ++ modres) { for(LL has7 = 0; has7 < 2; ++ has7) { LL nbit = i, nsum = sum + j, nmod = (modres+ten7[i-1]*j%7)%7,nhas = has7 | (j == 7); if( nsum <= sumlim + 9) { update(sum1[nbit][nsum][nmod][nhas], MOD( sum1[i-1][sum][modres][has7]+((ten[i-1]*j)%P)*f[i-1][sum][modres][has7]%P ) ); } } } } } } // sum2 for(LL i = 1; i <= 19; ++ i) { for(LL j = 0; j < 10; ++ j) { LL sumlim = (i-1) * 9; for(LL sum = 0; sum <= sumlim; ++ sum) { for(LL modres = 0; modres < 7; ++ modres) { for(LL has7 = 0; has7 < 2; ++ has7) { LL nbit = i, nsum = sum + j, nmod = (modres+ten7[i-1]*j%7)%7,nhas = has7 | (j == 7); if( nsum <= sumlim + 9) { LL tmp = 0, cnt = f[i-1][sum][modres][has7]; tmp = MOD(tmp + sum2[i-1][sum][modres][has7]); tmp = MOD(tmp + (ten[2*i-2]*j*j)%P*cnt%P); tmp = MOD(tmp + (ten[i-1]*j*2)%P*sum1[i-1][sum][modres][has7]%P); update(sum2[nbit][nsum][nmod][nhas], tmp ); } } } } } } } bool ok(LL x) { LL dsum = 0; if(x % 7 == 0) return true; while(x) { LL d = x % 10; if(d == 7) return true; dsum += d; x/=10; } return dsum %7 == 0; } LL mul(LL a, LL b, LL c) { a %= c; b %= c; return a*b % c; } LL gao(LL x) { if(x <= 0) return 0; LL ans = ok(x)?0:mul(x,x,P); //cout << x <<" ans = " << ans << endl; LL has7 = 0; LL sum = 0; LL modres = 0; LL pre = 0; LL d[22],dlen=0; while(x) d[dlen++]=x%10,x/=10; for(LL i = dlen-1,j=0;i>=0;--i,++j) { for(LL dg = 0; dg < d[i]; ++ dg) { for(LL dsum = 0; dsum <= i*9; ++ dsum) { for(LL md = 0; md < 7; ++ md) { for(LL msk = 0; msk < 2; ++ msk) { LL mdsum = dsum + dg + sum; LL tmp = (modres*10 + dg)%7; LL mmd = (ten7[i]*tmp+md)%7; LL mmsk = has7 | msk | (dg == 7); if( mmsk == 1 || mdsum % 7 ==0 || mmd == 0) continue; LL dd = (pre * 10 + dg) % P; LL cct = f[i][dsum][md][msk]; update(ans, sum2[i][dsum][md][msk]); update(ans, MOD(((dd*2%P)*ten[i])%P*sum1[i][dsum][md][msk]%P)); update(ans, ((((dd*dd%P)*ten[i])%P*ten[i])%P*cct)%P); } } } } if(d[i] == 7) has7 = 1; sum += d[i]; modres = (modres*10+d[i])%7; pre = pre * 10 + d[i]; } return ans; } int main(){ pre(); LL T; cin >> T; while(T --) { LL L, R; cin >> L >> R; cout << MOD( gao(R)-gao(L-1) ) <<endl; /* LL ans = 0; for(LL x = L; x <= R; ++ x) if(!ok(x)) update(ans, mul(x,x,P)); cout << ans << endl;*/ } return 0; }
problem
一个2*n位数,前n位数各位数和与后n位数各位数和相等,是lucky数。一个2*n位数,改变一个数字后,依然是2*n位(改前改后都没有前导零),并且是lucky数,则改之前的数称之为近似lucky数。求[l, r] 区间内,有多少近似lucky数。
think
dp[枚举到那一位][这个数是2*n位数][sum(前n位各位数和-后n位数各位数和)][more(最多增加)][less(最多减少)]sum可能<0 所以给他都+45more = max(9-前n位某个数, 后n位某个数)less = max(首位-1, 前n位且非首位的某个数, 9-后n位某个数) //因为首位不能变成0 所以首位-1答案是sum!=45(是0 的话就不用变了) && sum+more >=45 && sum-less<=45
code
const int M = 45; int f[10][10][91][10][10]; int b[11]; int dfs(int pos, int N, int sum, int more, int less, int e){ if(pos==0){ return sum!=M && sum+more>=M && sum-less<=M; } if(!e && ~f[pos][N][sum][more][less]) return f[pos][N][sum][more][less]; int ans = 0; int u = e?b[pos]:9; int d = pos==N?1:0; for(; d<=u; d++){ int ss = pos>N/2 ? sum+d : sum-d; int mm = pos>N/2 ? max(more, 9-d) : max(more, d); int ll = pos>N/2 ? max(less, pos==N?d-1:d) : max(less, 9-d); ans += dfs(pos-1, N, ss, mm, ll, e&&d==u); } return e ? ans : f[pos][N][sum][more][less] = ans; } int s(int n){ if(n==-1) return 0; int p = 0; while(n){ b[++p] = n%10; n/=10; } int ans = 0; for(int i=2; i<=p; i+=2){ ans += dfs(i, i, 0+M, 0, 0, i==p); } return ans; } int main(){ memset(f, -1, sizeof(f)); int a, b; while(~scanf("%d%d", &a, &b)){ printf("%d\n", s(b)-s(a-1)); } return 0; }
problem
[l, r] 区间内,有多少个数分解成K个不同B的次方。
think
平时写数位DP,习惯把数位按十进制分解,这道题,分解成B进制,就可以了。然后看有多少个数里面有K个1 其他都是0.
code
int K, B; int f[50][50]; int bit[50]; int dfs(int pos, int num, bool e){ if(pos==0) return num==K; if(!e && ~f[pos][num]) return f[pos][num]; int ans = 0; int u = e?bit[pos]:B-1; for(int d=0; d<=1 && d<=u; d++){ ans += dfs(pos-1, num+d, e&&d==u); } return e?ans:f[pos][num]=ans; } int s(int n){ int p = 0; while(n){ bit[++p] = n%B; n/=B; } return dfs(p, 0, true); } int main(){ int n, m; while(~scanf("%d%d%d%d", &n, &m, &K, &B)){ memset(f, -1, sizeof(f)); printf("%d\n", s(m)-s(n-1)); } return 0; }