攒了二三十个数位dp,持续更新
hdu 3555 Bomb
题意
- 1到n中含有连续49的数有多少。
思路
- 记忆化搜索求,不含连续49的,有49就continue。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
int bt[22];
ll dp[22][2];
ll dfs(int pos,int pre,bool limit){
if(pos==0)return 1;
if(!limit&&dp[pos][pre]!=-1)return dp[pos][pre];
int u=limit?bt[pos]:9;
ll ans=0;
rep(i,0,u){
if(pre==1&&i==9)continue;
ans+=dfs(pos-1,i==4,limit&&i==bt[pos]);
}
if(!limit)dp[pos][pre]=ans;
return ans;
}
ll gao(ll x){
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return dfs(pos,0,true);
}
int main(){
memset(dp,-1,sizeof(dp));
int T;
scanf("%d",&T);
while(T--){
ll x;
scanf("%lld",&x);
printf("%lld\n",x+1-gao(x));
}
return 0;
}
hdu 2089 不要62
题意
- 从l到r共有多少个数没有4,62.
思路
- 基本操作
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
int bt[10];
int dp[10][2];
int dfs(int pos,int pre,bool limit){
if(pos==0)return 1;
if(!limit&&dp[pos][pre]!=-1)return dp[pos][pre];
int u=limit?bt[pos]:9;
int res=0;
rep(i,0,u){
if(i==4)continue;
if(pre==1&&i==2)continue;
res+=dfs(pos-1,i==6,limit&&i==bt[pos]);
}
if(!limit)dp[pos][pre]=res;
return res;
}
int gao(int x){
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return dfs(pos,0,true);
}
int main(){
clr(dp,-1);
int x,y;
while(scanf("%d%d",&x,&y),x+y){
printf("%d\n",gao(y)-gao(x-1));
}
return 0;
}
CF 1036C Classy Numbers
题意
- 求从l到r的数中,非零位不超过3位的数有多少个。
思路
- 前边如果会了这题很简单。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
ll dp[22][4];
int bt[22];
ll dfs(int pos,int pre,bool limit){
if(pos==0)return 1;
if(!limit&&dp[pos][pre]!=-1)return dp[pos][pre];
int u=limit?bt[pos]:9;
ll res=0;
rep(i,0,u){
if(pre==3){
if(i!=0)continue;
}
if(i==0){
res+=dfs(pos-1,pre,limit&&i==bt[pos]);
}else{
res+=dfs(pos-1,pre+1,limit&&i==bt[pos]);
}
}
if(!limit)dp[pos][pre]=res;
return res;
}
ll gao(ll x){
memset(dp,-1,sizeof(dp));
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return dfs(pos,0,true);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
ll l,r;
scanf("%I64d%I64d",&l,&r);
ll ans=gao(r)-gao(l-1);
printf("%I64d\n",ans);
}
return 0;
}
bzoj 1026 [SCOI2009]windy数
题意
*从l到r有多少个数满足相邻两位相差至少为2
思路
*注意前导零
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
int bt[22];
ll dp[22][10];
ll dfs(int pos,int pre,bool limit,bool lead){
if(pos==0)return 1;
if(!limit&&!lead&&dp[pos][pre]!=-1)return dp[pos][pre];
int u=limit?bt[pos]:9;
ll res=0;
rep(i,0,u){
if(lead){
res+=dfs(pos-1,i,limit&&i==bt[pos],lead&&i==0);
}else{
if(abs(pre-i)<2)continue;
res+=dfs(pos-1,i,limit&&i==bt[pos],false);
}
}
if(!limit&&!lead)dp[pos][pre]=res;
return res;
}
ll gao(ll x){
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return dfs(pos,0,true,true);
}
int main(){
clr(dp,-1);
ll x,y;
scanf("%lld%lld",&x,&y);
printf("%lld",gao(y)-gao(x-1));
return 0;
}
poj 3252 Round Numbers
题意
- 求从l到r中(用二进制表示0的个数大于等于1的个数的数)的个数
思路
- 和十进制的差不多,见代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
int dp[35][35][35];
int bt[35];
int dfs(int pos,int cnt0,int cnt1,bool limit,bool lead){
if(pos==0)return cnt0>=cnt1;
if(!limit&&!lead&&dp[pos][cnt0][cnt1]!=-1)return dp[pos][cnt0][cnt1];
int u=limit?bt[pos]:1;
int res=0;
rep(i,0,u){
if(lead){
if(i==0){
res+=dfs(pos-1,cnt0,cnt1,limit&&i==bt[pos],true);
}else{
res+=dfs(pos-1,cnt0,cnt1+1,limit&&i==bt[pos],false);
}
}else{
if(i==0){
res+=dfs(pos-1,cnt0+1,cnt1,limit&&i==bt[pos],false);
}else{
res+=dfs(pos-1,cnt0,cnt1+1,limit&&i==bt[pos],false);
}
}
}
if(!limit&&!lead)dp[pos][cnt0][cnt1]=res;
return res;
}
int gao(int x){
int pos=0;
while(x){
bt[++pos]=x&1;
x>>=1;
}
return dfs(pos,0,0,true,true);
}
int main(){
clr(dp,-1);
int x,y;
scanf("%d%d",&x,&y);
printf("%d",gao(y)-gao(x-1));
return 0;
}
牛客小白月赛8 E 诡异数字
题意
- 从l到r有多少满足约束条件的数,约束条件有n个,分别是不超过连续len个x。
思路
- dp[ i ][ j ][ k ]表示从右数第i位,前有连续k个j。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
const int MOD=20020219;
int bt[22];
ll dp[22][10][22];
int a[10];
ll dfs(int pos,int now,int cnt,bool limit){
if(cnt>a[now])return 0;
if(pos==0)return 1;
if(!limit&&dp[pos][now][cnt]!=-1)return dp[pos][now][cnt];
int u=limit?bt[pos]:9;
ll res=0;
rep(i,0,u){
if(i==now){
res+=dfs(pos-1,i,cnt+1,limit&&bt[pos]==i);
}else{
res+=dfs(pos-1,i,1,limit&&bt[pos]==i);
}
}
if(!limit)dp[pos][now][cnt]=res;
return res;
}
ll gao(ll w){
int pos=0;
if(w==-1)return 0;
while(w){
bt[++pos]=w%10;
w/=10;
}
return dfs(pos,0,0,true);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
clr(dp,-1);
ll l,r;
int n;
scanf("%lld%lld%d",&l,&r,&n);
rep(i,0,9)a[i]=100;
while(n--){
int x,len;
scanf("%d%d",&x,&len);
a[x]=min(a[x],len);
}
printf("%lld\n",(gao(r)-gao(l-1))%MOD);
}
return 0;
}
牛客练习赛34 little w and Digital Root
题意
- 从l到r有多少个数处理之后分别得到1,2,3,4,5,6,7,8,9
- 这个处理就是这个数每一位数乘所在的位(1 base)再求和
- 递归处理到这个数小于10
思路
- 如果之前的会了,这个还是比较裸的,先预处理一下然后记忆化搜索
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
typedef long long ll;
int w[205];
ll dp[15][22][3000];
int bt[22];
ll dfs(int tp,int pos,int pre,bool limit){
if(pos==0)return tp==w[pre];
if(!limit&&dp[tp][pos][pre]!=-1)return dp[tp][pos][pre];
int u=limit?bt[pos]:9;
ll ans=0;
rep(i,0,u){
ans+=dfs(tp,pos-1,pre+i*pos,limit&&i==bt[pos]);
}
if(!limit)dp[tp][pos][pre]=ans;
return ans;
}
ll gao(int tp,ll x){
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return dfs(tp,pos,0,true);
}
int fun(int x){
if(x<10)return x;
int res=0;
int cnt=1;
while(x){
res+=cnt*(x%10);
cnt++;
x/=10;
}
return fun(res);
}
int main(){
memset(dp,-1,sizeof(dp));
rep(i,1,3000){
w[i]=fun(i);
}
int T;
cin>>T;
rep(kase,1,T){
ll l,r;
cin>>l>>r;
cout<<"Case #"<<kase<<":";
rep(i,1,9){
cout<<" "<<gao(i,r)-gao(i,l-1);
}
cout<<endl;
}
return 0;
}
LightOJ 1068 Investigation
题意
- 从x到y,有多少个数能被k整除且各位数之和同样能被k整除
思路
- 很容易看出k不会太大,因为所有位都是9,也很小。
- 然后就记忆化搜索,很简单。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define what_is(x) cerr<<#x<<" is "<<x<<endl;
typedef long long ll;
int bt[12];
int base[12];
int dp[12][105][105];
int k;
ll dfs(int pos,int pre1,int pre2,bool limit){
if(pos==0){
if(pre1==0&&pre2==0)return 1;
else return 0;
}
if(!limit&&dp[pos][pre1][pre2]!=-1)return dp[pos][pre1][pre2];
int u=limit?bt[pos]:9;
ll res=0;
rep(i,0,u){
res+=dfs(pos-1,(pre1+base[pos]*i)%k,(pre2+i)%k,limit&&i==bt[pos]);
}
if(!limit)dp[pos][pre1][pre2]=res;
return res;
}
ll gao(ll x){
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return dfs(pos,0,0,true);
}
int main(){
int T;
scanf("%d",&T);
rep(kase,1,T){
memset(dp,-1,sizeof(dp));
ll x,y;
scanf("%lld%lld%d",&x,&y,&k);
base[1]=1;
rep(i,2,12){
base[i]=(base[i-1]*10)%k;
}
int ans;
if(k>=100){
ans=0;
}else{
ans=gao(y)-gao(x-1);
}
printf("Case %d: %d\n",kase,ans);
}
return 0;
}
hdu 6148 Valley Numer
题意
- 从1到n有多少数满足先非增再非减,非增和非减也可以。
思路
- dp[ i ][ j ][ k ] 表示从右数第 i 位,上一位是 j 时,且为k状态时的数量。
- k为0是非增态,k为1是非减态
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
const int MOD=1e9+7;
ll dp[105][10][2];
char s[105];
int bt[105];
ll dfs(int pos,int pre,int tp,bool limit,bool lead){
if(pos==0)return 1;
if(!limit&&!lead&&dp[pos][pre][tp]!=-1)return dp[pos][pre][tp];
int u=limit?bt[pos]:9;
ll res=0;
rep(i,0,u){
if(lead){
if(i==0){
res+=dfs(pos-1,0,0,limit&&bt[pos]==i,true);
}else{
res+=dfs(pos-1,i,0,limit&&bt[pos]==i,false);
}
}else{
if(tp==0){
if(i<=pre){
res+=dfs(pos-1,i,0,limit&&bt[pos]==i,false);
}else{
res+=dfs(pos-1,i,1,limit&&bt[pos]==i,false);
}
}else{
if(i<pre)continue;
res+=dfs(pos-1,i,1,limit&&bt[pos]==i,false);
}
}
res%=MOD;
}
if(!limit&&!lead)dp[pos][pre][tp]=res;
return res;
}
int main(){
clr(dp,-1);
int T;
scanf("%d",&T);
while(T--){
scanf("%s",s);
int len=strlen(s);
int pos=0;
rep(i,0,len-1){
bt[++pos]=s[len-1-i]-'0';
}
printf("%lld\n",(dfs(pos,0,0,true,true)+MOD-1)%MOD);
}
return 0;
}
hihocoder 1301 筑地市场 二分+数位dp
题意
- 求第k个含有4或7的数,很裸。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
int bt[25];
ull dp[25];
ull dfs(int pos,bool limit){
if(pos==0)return 1;
if(!limit&&dp[pos]!=-1)return dp[pos];
int u=limit?bt[pos]:9;
ull res=0;
rep(i,0,u){
if(i==4||i==7)continue;
res+=dfs(pos-1,limit&&bt[pos]==i);
}
if(!limit)dp[pos]=res;
return res;
}
ull gao(ull x){
ull xx=x;
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return xx+1-dfs(pos,true);
}
int main(){
clr(dp,-1);
ull k;
cin>>k;
ull l=1,r=6e18,ans;
while(l<=r){
ull mid=(l+r)>>1;
if(gao(mid)>=k){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
cout<<ans;
return 0;
}
poj 3208 Apocalypse Someday 二分+数位dp
题意
- 求第n个有连续666的数
思路
- 二分求第x个符合条件的数
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
int bt[22];
int dp[22][3];
ll dfs(int pos,int pre,bool limit){
if(pos==0)return 1;
if(!limit&&dp[pos][pre]!=-1)return dp[pos][pre];
int u=limit?bt[pos]:9;
ll res=0;
rep(i,0,u){
if(i==6){
if(pre==2)continue;
res+=dfs(pos-1,pre+1,limit&&bt[pos]==i);
}else{
res+=dfs(pos-1,0,limit&&bt[pos]==i);
}
}
if(!limit)dp[pos][pre]=res;
return res;
}
ll gao(ll x){
ll xx=x;
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return xx+1-dfs(pos,0,true);
}
int main(){
clr(dp,-1);
int T;
scanf("%d",&T);
while(T--){
ll n;
scanf("%lld",&n);
ll l=1,r=1e18,ans;
while(l<=r){
ll mid=(l+r)>>1;
if(gao(mid)>=n){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
printf("%lld\n",ans);
}
return 0;
}
CF 1073E Segment Sum
题意
- 从l到r有多少个数满足有k位不同的数
- 好题,复习的时候就刷这个
思路
- 状压一下,dfs
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define clr(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define SZ(x) ((int)(x).size())
typedef unsigned long long ull;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pii;
/*************head******************/
const ll MOD=998244353;
ll l,r;
int k;
pair<ll,ll> dp[22][1<<11];
bool vis[22][1<<11];
ll base[22];
int bt[22];
int fun(int x){
int res=0;
while(x){
res++;
x-=x&-x;
}
return res;
}
pair<ll,ll> dfs(int pos,int pre,bool limit,bool lead){
if(pos==0)return fun(pre)<=k?mp(1,0):mp(0,0);
if(!limit&&!lead&&vis[pos][pre])return dp[pos][pre];
int u=limit?bt[pos]:9;
pair<ll,ll> res=mp(0,0);
for(int i=0;i<=u;i++){
int now=pre;
if(lead&&i==0){
now=0;
}else{
now=pre|(1<<i);
}
pair<ll,ll> tmp=dfs(pos-1,now,limit&&i==bt[pos],lead&&i==0);
res.first=(res.first+tmp.first)%MOD;
ll w=1LL*i*base[pos]%MOD;
w=(w*tmp.first)%MOD;
res.second=(res.second+tmp.second+w)%MOD;
}
if(!limit&&!lead)dp[pos][pre]=res,vis[pos][pre]=true;
return res;
}
ll gao(ll x){
int pos=0;
while(x){
bt[++pos]=x%10;
x/=10;
}
return dfs(pos,0,true,true).second;
}
int main(){
base[1]=1;
for(int i=2;i<=21;i++){
base[i]=base[i-1]*10%MOD;
}
scanf("%I64d%I64d%d",&l,&r,&k);
printf("%I64d",(gao(r)-gao(l-1)+MOD)%MOD);
return 0;
}