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\n",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;
}