题目链接
坑:
1.ll x,y;
z=x*y;可能会溢出,于是我写成x%mod*y%mod
仍旧错误,要写成x%mod*(y%mod).
2.f(9019)=1.
要注意如果为0,下一位的符号根据0的个数而变化
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<queue> 5 #include<math.h> 6 #include<string.h> 7 #include<string> 8 #include<stdlib.h> 9 using namespace std; 10 typedef long long ll; 11 typedef unsigned long long ull; 12 #define re(i,n) for(int i=0;i<n;i++) 13 const int mod = 1e9 + 7; 14 /* 15 Node cnt表示个数,sum表示和 16 */ 17 struct Node{ 18 ll cnt, sum; 19 Node() :cnt(0), sum(0){} 20 Node(ll c, ll s) :cnt(c), sum(s){} 21 }dp[19][2][2][600];//(bits,+-,+-can change,sum) 22 /* 23 19 最多19位 24 2 +还是- 25 2 是否是第一个数字 26 600 f(n)的结果,因为19位*9=171,输入的k是-100到100,所以范围大概是-300到+300,所以用600 27 */ 28 ll ten[19]; 29 //ten[i]表示10^i 30 void init(){ 31 ten[0] = 1; 32 for (int i = 1; i < 19; i++){ 33 ten[i] = 10 * ten[i - 1]; 34 } 35 } 36 /*d是一个大管家,管理者dp这个数组,如果计算过,那就不再计算了 37 对参数做一些处理,像适配器一样 38 n表示[0,10^n-1]范围内,第一个符号为flag,符号是否会改变change,f(n)=k 39 */ 40 Node d(int n, int flag, int change, int k){ 41 int ff = (flag == 1 ? 1 : 0); 42 int kk = k + 300; 43 Node f(ll,int, int, int); 44 if (dp[n][ff][change][kk].cnt == -1){ 45 dp[n][ff][change][kk] = f(ten[n] - 1, flag, change, k); 46 } 47 return dp[n][ff][change][kk]; 48 } 49 /* 50 主要逻辑都在这个函数里面,n表示[0,n]范围内的值 51 */ 52 Node f(ll n, int flag, int change, int k){ 53 if (n < 0)return Node(0, 0); 54 if (n < 10){ 55 if (flag*k >= 0 && flag*k <= n)return Node(1, flag*k); 56 else return Node(0, 0); 57 } 58 ll mi = 0, h = 0; 59 for (ll tmp = n; tmp; tmp /= 10)h = tmp % 10, mi++; 60 mi--; 61 ll va = h*ten[mi];//处理清楚最高位 62 Node t = d(mi, change ? 1 : -flag, change, k); //第一位为0时,有多少种情况 63 Node ans = t; 64 for (int i = 1; i < h; i++){ 65 t = d(mi, -flag, 0, k - flag*i); 66 ans.cnt += t.cnt; 67 ans.sum = (ans.sum + ten[mi]%mod*i*( t.cnt%mod) + t.sum) % mod; 68 } 69 //第一位为h时的情况 70 int ff = ((mi&1)?flag:-flag); 71 for (ll tmp=n-va; tmp; tmp/=10){ 72 ff *= -1; 73 } 74 t = f(n - va, ff, 0, k - flag*h); 75 ans.cnt += t.cnt; 76 ans.sum = (ans.sum + va%mod*(t.cnt%mod) + t.sum) % mod; 77 return ans; 78 } 79 int main(){ 80 //freopen("in.txt", "r", stdin); 81 init(); 82 memset(dp, -1, sizeof(dp)); 83 ll l, r, k; 84 cin >> l >> r >> k; 85 Node m = f(l - 1, 1,1, k), n = f( r, 1,1, k); 86 ll ans = (n.sum - m.sum) % mod; 87 if (ans < 0)ans += mod; 88 cout << ans << endl; 89 return 0; 90 }
别人的代码还精简,算法更好.
1 struct node 2 { 3 ll cnt,sum; //分别表示该状态的出现的次数,以及数字和 4 node(ll _cnt,ll _sum):cnt(_cnt),sum(_sum){} 5 node(){} 6 }dp[20][20][300]; //dp[i][j][k],表示当前在的i位,第一位有效位为j,交错和为k-100的状态 7 ll num[20]; 8 ll ten[20]; 9 ll l,r; 10 int k; 11 node dfs(int cur,int first,int sum,bool limit) 12 { 13 if(cur <= 0) 14 return node(sum==k,0); 15 if(!limit && dp[cur][first][sum+100].cnt != -1) return dp[cur][first][sum+100]; 16 int up = limit ? num[cur] : 9; 17 node ret(0,0),tv; 18 rep(i,up+1) 19 { 20 int g; 21 if(!first){ g = (i == 0 ? 0 : cur); } 22 else g = first; 23 if(g) 24 tv = dfs(cur-1,g,sum+((g-cur)%2==0?1:-1)*i,limit && i == up); 25 else 26 tv = dfs(cur-1,0,0,limit && i==up); 27 ll t = i*ten[cur-1]%mod; 28 ret.cnt = (ret.cnt + tv.cnt) % mod; //次数相加 29 ret.sum = (ret.sum + tv.sum + t*tv.cnt)%mod; //和相加 30 } 31 if(!limit) dp[cur][first][sum+100] = ret; 32 return ret; 33 } 34 ll solve(ll n) 35 { 36 if(n <= 0) return 0; 37 int len = 0; 38 while(n){ 39 num[++len] = n % 10; 40 n /= 10; 41 } 42 return dfs(len,0,0,1).sum; 43 } 44 void init() 45 { 46 memset(dp,-1,sizeof(dp)); 47 ten[0] = 1; 48 for(int i=1;i<20;i++) ten[i] = (ten[i-1] * 10) % mod; 49 } 50 int main() 51 { 52 #ifndef ONLINE_JUDGE 53 freopen("in.txt","r",stdin); 54 // freopen("out.txt","w",stdout); 55 #endif 56 init(); 57 while(~scanf("%lld%lld%d",&l,&r,&k)) 58 { 59 cout<<(solve(r)-solve(l-1)+mod)%mod<<'\n'; 60 } 61 return 0; 62 }