目录
[WOJ1516]Amount of degrees
转化为对应进制, 即求改进制下L--R直接有多少个x, 满足x的B进制有K个1
#include<bits/stdc++.h>
using namespace std;
int L, R, K, B, a[50];
int f[50][20];
int dfs(int u,int cnt,int limit,int zero){
if(u == 0) return (cnt == K);
if(f[u][cnt] != -1 && !limit && !zero) return f[u][cnt];
int ans = 0, to = limit ? a[u] : B-1;
for(int i=0;i<=min(to, 1);i++) ans += dfs(u-1, cnt+i, limit && i==to, zero && i==0);
if(!limit && !zero) f[u][cnt] = ans;
return ans;
}
int Solve(int x){
int num = 0; memset(f, -1, sizeof(f));
while(x){a[++num] = x % B; x /= B;}
return dfs(num, 0, 1, 1);
}
int main(){
scanf("%d%d%d%d",&L,&R,&K,&B);
printf("%d",Solve(R) - Solve(L-1));
}
[WOJ1120]数字计数
记忆化搜索就完了, 注意前导0的影响
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL L, R, ans[12], Need; int a[15];
LL f[10][15][15];
LL dfs(int u,LL sum,int limit,int zero){
if(u == 0) return sum;
if(!limit && !zero && f[Need][u][sum]!=-1) return f[Need][u][sum];
int up = limit ? a[u] : 9; LL ans = 0;
for(int i=0; i<=up; i++){
if(i==0 && zero) ans += dfs(u-1, sum, limit && (i==up), zero && (i==0));
else ans += dfs(u-1, sum + (Need==i), limit && (i==up), zero && (i==0));
} if(!limit && !zero) f[Need][u][sum] = ans;
return ans;
}
LL Solve(LL x){
int num = 0;
while(x){ a[++num] = x%10; x /= 10;}
return dfs(num, 0, 1, 1);
}
int main(){
memset(f, -1, sizeof(f));
scanf("%lld%lld",&L,&R);
for(int i=0;i<=9;i++){ Need = i;
cout<< Solve(R) - Solve(L-1) << " ";
} return 0;
}
[WOJ1505]美丽数
因为lcm(1--9) = 2520, 所以我们将每个数%2520是什么记下来就可以了
另外还要判断每个数出现没有, 状压就可以了, 取模有个优化, 模252就可以了(玄学, 证明不会)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL L, R, f[20][252][512]; int a[20];
int check(int Mod,int state){
for(int i=1;i<=9;i++){
if(state & (1<<(i-1))){
if(Mod % i) return 0;
}
} return 1;
}
LL dfs(int u,int Mod,int state,int limit){
if(u == 0) return check(Mod, state);
Mod %= 252;
if(!limit && f[u][Mod][state]!=-1) return f[u][Mod][state];
int up = limit ? a[u] : 9; LL ans = 0;
for(int i=0;i<=up;i++){
if(i == 0) ans += dfs(u-1, Mod*10, state, limit && (i==up));
else ans += dfs(u-1, Mod*10 + i, state|(1<<(i-1)), limit && (i==up));
}
if(!limit) f[u][Mod][state] = ans;
return ans;
}
LL calc(LL x){
int num = 0;
while(x){a[++num] = x%10; x /= 10;}
return dfs(num, 0, 0, 1);
}
int main(){
memset(f, -1, sizeof(f));
while(~scanf("%lld%lld",&L,&R)){
printf("%lld\n",calc(R) - calc(L-1));
} return 0;
}
[WOJ1132]self同类分布
很明显可以想到枚举数字和
枚举tot, Mod对tot取模
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL L, R; int Mod, a[20];
LL f[20][200][200];
LL dfs(int u,int res,int sum,int limit){
res %= Mod;
if(u == 0) return (!res && sum == Mod);
if(sum > Mod) return 0;
if(!limit && f[u][res][sum]!=-1) return f[u][res][sum];
int up = limit ? a[u] : 9; LL ans = 0;
for(int i=0;i<=up;i++){
ans += dfs(u-1, res*10 + i, sum + i, limit&(i==up));
} if(!limit) f[u][res][sum] = ans; return ans;
}
LL Solve(LL x){
int num = 0;
while(x){a[++num] = x % 10; x /= 10;}
LL ans = 0;
for(int i=1;i<=num*9;i++){
memset(f, -1, sizeof(f));
Mod = i; ans += dfs(num, 0, 0, 1);
} return ans;
}
int main(){
scanf("%lld%lld",&L,&R);
printf("%lld",Solve(R) - Solve(L-1));
}
[WOJ1218]odd-even number
发现只需记录上一位是奇数还是偶数, 长度是奇数还是偶数, 前导0特殊处理, 记忆化搜索时讨论一下就可以了
#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL L, R; int T, a[20]; LL f[20][2][2];
LL dfs(int u,int len,int val,int limit,int zero){
if(u == 0) return (len ^ val);
if(!limit && !zero && f[u][len][val] != -1) return f[u][len][val];
int up = limit ? a[u] : 9; LL ans = 0;
for(int i=0;i<=up;i++){
if(zero) ans += dfs(u-1, 1, i & 1, limit & (i==up), zero & (i==0));
else{
if(i & 1){
if(len ^ val) ans += dfs(u-1, 1, 1, limit & (i==up), zero & (i==0));
if(len == 1 && val == 1) ans += dfs(u-1, 0, 1, limit & (i==up), zero & (i==0));
}
else{
if(len == 0) ans += dfs(u-1, 1, 0, limit & (i==up), zero & (i==0));
if(len == 1 && val == 0) ans += dfs(u-1, 0, 0, limit & (i==up), zero & (i==0));
}
}
} if(!limit && !zero) f[u][len][val] = ans;
return ans;
}
LL Solve(LL x){
int num = 0;
while(x){ a[++num] = x%10; x /= 10;}
return dfs(num, 1, 0, 1, 1);
}
int main(){
scanf("%d",&T);
memset(f, -1, sizeof(f));
for(int d=1; d<=T; d++){
scanf("%lld%lld",&L,&R);
cout<<"Case #"<<d<<": ";
cout<< Solve(R) - Solve(L-1) << '\n';
} return 0;
}
[WOJ1517]Sorted bit sequence
挺有意思的一道题, 一般数位DP求k大都是二分答案
首先1的个数可以二分, 当我们确定1的个数后, 相当于在某个特定的1的个数中找原数的第k大, 又可以二分
于是两次数位DP, 负数按题目要求变换就可以了
#include<bits/stdc++.h>
#define inf ((1ll<<32)-1)
typedef long long LL;
using namespace std;
LL L, R, k, Up, a[35], f[35][35];
LL dp1(LL u,LL sum,LL limit){
if(u == 0) return (sum <= Up);
if(!limit && f[u][sum]!=-1) return f[u][sum];
LL up = limit ? a[u] : 1, ans = 0;
for(LL i=0;i<=up;i++){
ans += dp1(u-1, sum+i, limit&&(i==up));
} if(!limit) f[u][sum] = ans;
return ans;
}
LL calc(LL x){
if(x < 0) return 0;
LL num = 0;
while(x){
a[++num] = x % 2;
x /= 2;}
return dp1(num, 0, 1);
}
LL dp2(LL u,LL sum,LL limit){
if(u == 0){
return (sum == Up);
}
if(!limit && f[u][sum] != -1) return f[u][sum];
LL up = limit ? a[u] : 1, ans = 0;
for(LL i=0;i<=up;i++){
ans += dp2(u-1, sum+i, limit&&(i==up));
} if(!limit) f[u][sum] = ans;
return ans;
}
LL Solve(LL x){
if(x < 0) return 0;
LL num = 0; memset(f, -1, sizeof(f));
while(x){ a[++num] = x % 2; x /= 2;}
return dp2(num, 0, 1);
}
int main(){
scanf("%lld%lld%lld",&L,&R,&k); int flag = 0;
if(L<0) L = -L, R = -R, L--, R--, L = inf-L, R = inf-R, flag = 1;
LL l = 0, r = 31;
while(l<r){
memset(f, -1, sizeof(f));
LL mid = (l+r) >> 1; Up = mid;
if(calc(R) - calc(L-1) > k) r = mid;
else l = mid+1;
}
memset(f, -1, sizeof(f));
Up = l-1; k -= (calc(R) - calc(L-1));
Up = l; k += Solve(L-1); l = L, r = R;
while(l<r){
LL mid = (l+r) >> 1;
if(Solve(mid) >= k) r = mid;
else l = mid+1;
}
if(!flag) cout<<l; else cout<<-(inf-l)-1;
return 0;
}
[WOJ2755] [CQOI2016]手机号码
记录上一次和上上次的数, 4, 8 有无出现, 然后就是模板了
#include<bits/stdc++.h>
#define LL long long
LL L, R; int a[15];
LL f[20][2][15][15][2][2];
LL dfs(int u, int already, int las1, int las2, int is4, int is8, int limit){
if(is4 && is8) return 0;
if(u == 0) return already;
LL &res = f[u][already][las1][las2][is4][is8];
if(!limit && res != -1) return res;
int up = limit ? a[u] : 9; LL ans = 0;
for(int i=0; i<=up; i++){
ans += dfs(u-1, already||(i==las1 && i==las2), i, las1, is4||(i==4), is8||(i==8), limit&&(i==up));
} if(!limit) res = ans;
return ans;
}
LL Solve(LL x){
if(x < 1e10) return 0;
memset(f, -1, sizeof(f)); int num = 0;
while(x){ a[++num] = x % 10, x /= 10;}
LL ans = 0;
for(int i=1;i<=a[num];i++)
ans += dfs(num-1, 0, i, 0, (i==4), (i==8), i == a[num]);
return ans;
}
int main(){
scanf("%lld%lld",&L,&R);
printf("%lld", Solve(R) - Solve(L-1));
return 0;
}