CodeForces 55D : Beautiful numbers
题意 : 求 【L,R】之间能被自己每一位非0数整除的数的个数。
1-9的LCM是比较小的, 但是直接开会爆, 需要离散化, 这题关键 lcm 和 离散了
#include<bits/stdc++.h> using namespace std; const int maxn = 2520; int gcd(int a, int b) {return b ? gcd(b, a%b): a; } int lcm(int a, int b) {return a / gcd(a, b) * b; } int index[maxn + 50]; void Get_Index() { int l = 0; for(int i = 1; i <= maxn; ++i) { if(maxn % i == 0) index[i] = l++; } } typedef long long LL; LL Dp[50][maxn][100]; int Num[100]; LL DFS(int L, int sum, int mod, bool e) { if(L == -1) return sum % mod == 0; if(!e && Dp[L][sum][index[mod]] != -1) return Dp[L][sum][index[mod]]; int u = e ? Num[L] : 9; LL ret = 0; for(int i = 0; i <= u; ++i) ret += DFS(L-1, (sum*10+i)%maxn, i?lcm(mod, i):mod, e&&(i==u)); return e ? ret : Dp[L][sum][index[mod]] = ret; } LL Solve(LL N) { int L = 0; while(N) { Num[L++] = N%10; N/=10; } return DFS(L-1,0,1,1); } int main() { Get_Index(); int t; LL A, B; cin >> t; memset(Dp, -1, sizeof(Dp)); while(t--) { cin >> A >> B; LL Ans = A ? (Solve(B)-Solve(A-1)) : Solve(B); cout << Ans << endl; } }
题意 : 求数字的位数数升序刚好为 K 的数的个数。
直接状态不好开, 平常我们求LIS 的思想, 可以转化, 状态压缩, 用二进制的 1 的个数表是 LIS 的长度
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 1<<11; LL Dp[20][maxn][11]; LL Num[20], A, B, K; int GetOne(int s) { int ret = 0; while(s) { if(s & 1) ret ++; s >>= 1; } return ret; } int GetState(int n, int s) { /// 运用 二分求 LIS 的思想 for(int i = n; i < 10; ++i) if(s&(1<<i)) return (s^(1<<i))|(1<<n); return s|(1<<n); } LL DFS(int L, int state, bool isz, bool e) { if(L == -1) return GetOne(state) == K; if(!e && Dp[L][state][K] != -1) return Dp[L][state][K]; int u = e ? Num[L] : 9; LL ret = 0; for(int i = 0; i <= u; ++i) ret += DFS(L-1, (isz&&(i==0))?0:GetState(i,state), (isz&&(i==0)), e&&(i==u)); return e ? ret : Dp[L][state][K] = ret; } LL Solve(LL N) { int L = 0; while(N) { Num[L++] = N % 10; N /= 10; } return DFS(L-1, 0, 1, 1); } int main() { memset(Dp,-1,sizeof(Dp)); int t; scanf("%d", &t); for(int kase = 1; kase <= t; ++kase) { scanf("%lld %lld %lld", &A, &B, &K); printf("Case #%d: %lld ",kase, Solve(B)-Solve(A-1)); } }
HDU 2089 不要62 、 HDU 3555Bomb、 POJ 3252 (转换成二进制数)
经典熟悉板子的题了
题意 : 求出 平衡数的个数, 类似杠杆, 利用 权值和为 0 , 枚举中心就好了
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 20; LL Num[20], Dp[20][20][1000][2]; LL DFS(int L, int mid, int sum, bool e) { if(L == -1) return sum ? 0 : 1; if(!e && Dp[L][mid][sum][e]!= -1) return Dp[L][mid][sum][e]; LL ret = 0; int u = e ? Num[L] : 9; for(int i = 0; i <= u; ++i) { int tmp = (L-mid) * i + sum; if(tmp >= 0) ret += DFS(L-1, mid, tmp, e && (i==u)); } return e ? ret : Dp[L][mid][sum][e] = ret; } LL Solve(LL N) { int L = 0; while(N) { Num[L++] = N % 10; N /= 10; } /// LL Ans = 0; for(int i = 0; i < L; ++i) { memset(Dp,-1,sizeof(Dp)); Ans += DFS(L-1, i, 0, 1)-1; } return Ans + 1; } int main() { int t; LL A, B; cin >> t; while(t--) { cin >>A >> B; cout << Solve(B)-Solve(A-1) <<endl; } return 0; }
题目转换成求平方和;
需要数学公式先推导一下,
(a+b1)^2 + (a+b2)^2 + ... + (a+bn)^2 = n*a^2 + 2*a*(b1+b2+...+bn) + (b1^2 + b2^2 + ... + bn^2)
保存 num 个数 , sum 和, sum2 平方和三个状态,就可以快速求出值了。
#include<bits/stdc++.h> using namespace std; typedef long long LL; const LL MOD = 1e9 + 7; struct Node { LL num, sum, sum2; Node(LL a = 0, LL b = 0, LL c = 0) : num(a), sum(b), sum2(c) {} }; bool Vis[30][10][10]; Node Dp[30][10][10]; LL Num[30]; LL Pow[30]; void INIT() { memset(Vis, 0, sizeof(Vis)); Pow[0] = 1; for(int i = 1 ; i < 20; ++i) Pow[i] = Pow[i-1]*10; } Node DFS(LL Len, LL Sum, LL Mod, bool e) { if(Len == -1) { if(Sum == 0 || Mod == 0) return Node(0,0,0); else return Node(1,0,0); } if(!e && Vis[Len][Sum][Mod]) return Dp[Len][Sum][Mod]; int u = e ? Num[Len] : 9; Node ret, tmp; for(int i = 0; i <= u; ++i) { if(i == 7) continue ; tmp = DFS(Len-1, (Sum+i) % 7, (Mod*10+i) % 7, e && (i==u)); LL d = i * (Pow[Len] % MOD) % MOD; ret.num = (tmp.num + ret.num) % MOD; ret.sum = (d * tmp.num % MOD + tmp.sum + ret.sum) % MOD; ret.sum2 = (d*d%MOD*tmp.num%MOD + tmp.sum2 + ret.sum2 + 2 * d * tmp.sum % MOD) % MOD; } if(!e) { Vis[Len][Sum][Mod] = true; Dp[Len][Sum][Mod] = ret; } return ret; } LL Solve(LL N) { int L = 0; while(N) { Num[L++] = N % 10; N /= 10; } return DFS(L-1, 0, 0, 1).sum2; } int main() { INIT(); int t; cin >> t; LL L, R; while(t--) { cin >> L >> R; cout << (Solve(R) - Solve(L-1) + MOD) % MOD << endl; } return 0; }