hdu2089 不要62
题意:
求[l,r]内满足下列条件的数的个数:
1.不含4
2.不含连续62(连续的例如623,不连续的例如602)
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=10;//题目数据范围最大1e6,即最多7位
int digit[maxm];//数位分解
int d[maxm][2];//d[i][0]表示长度为i,首位不为6方案数;d[i][1]表示长度为i,首位为6方案数
int dfs(int len,bool pre6,bool limit){//pre6记录上一位是否是6,limit最高位标记
if(!len)return 1;
if(!limit&&d[len][pre6]!=-1){
return d[len][pre6];
}
int ans=0;
int ma=(limit?digit[len]:9);//确定枚举上界
for(int i=0;i<=ma;i++){
if(i==4)continue;//4不行
if(i==2&&pre6)continue;//62连续也不行
ans+=dfs(len-1,i==6,limit&&i==ma);
}
if(!limit){//只记录没有首位限制的
d[len][pre6]=ans;
}
return ans;
}
int solve(int x){
int len=0;
memset(digit,0,sizeof digit);
while(x){//数位分解
digit[++len]=x%10;
x/=10;
}
return dfs(len,false,true);
}
signed main(){
memset(d,-1,sizeof d);//外面初始化一次就行了
int l,r;
while(scanf("%d%d",&l,&r)!=EOF){
if(!(l+r))break;
int ans=solve(r)-solve(l-1);
printf("%d\n",ans);
}
return 0;
}
hdu4734 F(x)
题意:
定义F(x)=An2n-1 + An-12n-2 + … + A221 + A120.
给a,b求0-b中满足f(x)<=f(a)的x的个数
思路:
f(a)是根据输入变化的
容易想到记录长度为len,f(x)为sum,f(a)为fa时候的状态d(len,sum,fa),则需要三维。
经测试f(a)最大在4599,三维显然开不起,
因为题目求得是小于等于f(a)得,把题目转化成减法,从f(a)开始减,
则数组可以改成长度为len,当前剩余remain得方案数d(len,remain),二维就没问题了。
code:
#include<bits/stdc++.h>
using namespace std;
const int N=15;
const int M=5e3+5;
int digit[N];
int d[N][M];
int f(int x){
int ans=0;
int p=1;
while(x){
ans+=x%10*p;
x/=10;
p<<=1;
}
return ans;
}
int dfs(int len,int remain,int limit){
if(!len)return remain>=0;
if(remain<0)return 0;
if(!limit&&d[len][remain]!=-1){
return d[len][remain];
}
int ans=0;
int ma=(limit?digit[len]:9);
for(int i=0;i<=ma;i++){
ans+=dfs(len-1,remain-i*(1<<(len-1)),limit&&i==ma);
}
if(!limit){
d[len][remain]=ans;
}
return ans;
}
int solve(int a,int x){
int len=0;
while(x){
digit[++len]=x%10;
x/=10;
}
return dfs(len,f(a),1);
}
signed main(){
memset(d,-1,sizeof d);
int T;
scanf("%d",&T);
int cas=1;
while(T--){
int a,b;
scanf("%d%d",&a,&b);
int ans=solve(a,b);
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}
poj3252 Round Numbers
题意:
求[l,r]中二进制0的个数大于等于1的个数的数
思路:
d(len,dif)表示长度为len的二进制数,其中0的个数减1的个数差值为dif的方案数
中间过程dif可能小于0无法作为数组下标,因为int最小不到-32,加上32再存就行了。
code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxm=65;
int digit[maxm];
int d[maxm][maxm];
int dfs(int len,int dif,bool lead,bool limit){
if(!len)return dif>=0;
if(!lead&&!limit&&d[len][dif+32]!=-1){//加上32保证不为负数
return d[len][dif+32];
}
int ma=(limit?digit[len]:1);
int ans=0;
for(int i=0;i<=ma;i++){
if(lead&&i==0){
ans+=dfs(len-1,dif,true,limit&&i==ma);//前导零不计,所以dif不变
}else{
ans+=dfs(len-1,dif+(i==0?1:-1),false,limit&&i==ma);
}
}
if(!lead&&!limit){
d[len][dif+32]=ans;
}
return ans;
}
int solve(int x){
int len=0;
while(x){
digit[++len]=(x&1);
x>>=1;
}
return dfs(len,0,true,true);
}
signed main(){
memset(d,-1,sizeof d);
int l,r;
while(scanf("%d%d",&l,&r)!=EOF){
int ans=solve(r)-solve(l-1);
printf("%d\n",ans);
}
return 0;
}
P2657 [SCOI2009]windy数
题意:
不含前导零且相邻两个数字之差至少为2的正整数被称为windy数
问[l,r]之间有多少windy数
思路:
d(len,pre)表示长度为len,上一位为pre的方案数
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=15;
int digit[maxm];
int d[maxm][maxm];
int dfs(int len,int pre,bool lead,bool limit){
if(!len)return 1;
if(!lead&&!limit&&d[len][pre]!=-1){
return d[len][pre];
}
int ans=0;
int ma=(limit?digit[len]:9);
for(int i=0;i<=ma;i++){
if(lead){//前导零的情况不用考虑差值
ans+=dfs(len-1,i,lead&&i==0,limit&&i==ma);
}else{//无前导的情况需要考虑差值
if(abs(pre-i)<2)continue;//差值小于2跳过
ans+=dfs(len-1,i,false,limit&&i==ma);
}
}
if(!lead&&!limit){
d[len][pre]=ans;
}
return ans;
}
int solve(int x){
int len=0;
while(x){
digit[++len]=x%10;
x/=10;
}
return dfs(len,0,true,true);
}
signed main(){
memset(d,-1,sizeof d);
int l,r;
scanf("%d%d",&l,&r);
int ans=solve(r)-solve(l-1);
printf("%d\n",ans);
return 0;
}
hdu3555 Bomb
题意:
给n,求1-n内有多少个数含有连续的49
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=20;
int digit[maxm];
int d[maxm][maxm];
int ten[maxm];
void init(){
memset(d,-1,sizeof d);
ten[0]=1;
for(int i=1;i<=18;i++){//预处理10的各个幂,dfs中要用到
ten[i]=ten[i-1]*10;
}
}
int dfs(int n,int len,bool pre,bool limit){//pre记录上一位是否为4
if(!len)return 0;//这里是0
if(!limit&&d[len][pre]!=-1){
return d[len][pre];
}
int ans=0;
int ma=(limit?digit[len]:9);
for(int i=0;i<=ma;i++){
if(pre&&i==9){//如果有连续49,直接记录答案
ans+=(limit?n%ten[len-1]+1:ten[len-1]);
}else{
ans+=dfs(n,len-1,i==4,limit&&i==ma);
}
}
if(!limit){
d[len][pre]=ans;
}
return ans;
}
int solve(int x){
int n=x;
int len=0;
while(x){
digit[++len]=x%10;
x/=10;
}
return dfs(n,len,false,true);
}
signed main(){
init();
int T;
cin>>T;
while(T--){
int n;
cin>>n;
int ans=solve(n);
cout<<ans<<endl;
}
return 0;
}
codeforces204 A. Little Elephant and Interval
题意:
求[l,r]内有多少个数首尾相同
l,r<=1e18
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=25;
int digit[maxm];
int d[maxm][maxm];//d[i][j]表示剩余长度为i,当前首位为j的方案数
int dfs(int len,int st,int ed,int limit,int pre){
//长度,首位,尾位,最高位限制,前导零
if(!len)return st==ed;
if(!limit&&d[len][st]!=-1){
return d[len][st];
}
int ans=0;
int ma=(limit?digit[len]:9);
for(int i=0;i<=ma;i++){
int a=st;
int b=ed;
if(pre){//如果有前导零则i为首位
a=i;//st=i;
}
if(len==1){//如果是最后一位
b=i;//ed=i;
}
ans+=dfs(len-1,a,b,limit&&i==ma,pre&&i==0);
}
if(!limit){
d[len][st]=ans;
}
return ans;
}
int solve(int n){
int len=0;
while(n){
digit[++len]=n%10;
n/=10;
}
return dfs(len,0,0,1,1);
}
signed main(){
memset(d,-1,sizeof d);
int l,r;
while(cin>>l>>r){
cout<<solve(r)-solve(l-1)<<endl;
}
return 0;
}
codeforces1036 C. Classy Numbers
题意:
给l,r,求区间[l,r]内有多少个数,满足数位不为0的个数小于等于3
思路:
d(len,now)表示长度为len,还能选择now个不为0的数的方案数
dfs过程中如果now<0,则直接返回0
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=25;
int digit[maxm];
int d[maxm][4];
int dfs(int len,int limit,int now){
if(now<0)return 0;//超过3个不符合条件
if(!len)return 1;
if(!limit&&d[len][now]!=-1){
return d[len][now];
}
int ma=(limit?digit[len]:9);
int ans=0;
for(int i=0;i<=ma;i++){
ans+=dfs(len-1,limit&&(i==ma),now-(i!=0));
}
if(!limit){
d[len][now]=ans;
}
return ans;
}
int solve(int n){
int len=0;
while(n){
digit[++len]=n%10;
n/=10;
}
return dfs(len,1,3);
}
signed main(){
memset(d,-1,sizeof d);
int T;
cin>>T;
while(T--){
int l,r;
cin>>l>>r;
cout<<solve(r)-solve(l-1)<<endl;
}
return 0;
}
牛客 好朋友
题面:
思路:
dfs的过程中添加一个状态变量sta
一共四种状态:
0.啥都没有
1.0
2.00
3.007
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=25;
int digit[maxm];
int d[maxm][4];//d[i][j]表示剩余长度为i,当前状态为sta的方案数
int dfs(int len,int sta,int limit,int pre){
//长度,状态,数位限制,前导0
if(!len)return sta==3;//007状态
if(!limit&&!pre&&d[len][sta]!=-1)return d[len][sta];
int ma=limit?digit[len]:9;
int ans=0;
for(int i=0;i<=ma;i++){//枚举当前位
if(sta==0){//啥都没有
ans+=dfs(len-1,!pre&&i==0,limit&&i==ma,pre&&i==0);
}else if(sta==1){//0
ans+=dfs(len-1,sta+(i==0),limit&&i==ma,pre&&i==0);
}else if(sta==2){//00
ans+=dfs(len-1,sta+(i==7),limit&&i==ma,pre&&i==0);
}else if(sta==3){//007
ans+=dfs(len-1,sta,limit&&i==ma,pre&&i==0);
}
}
if(!limit&&!pre){
d[len][sta]=ans;
}
return ans;
}
int solve(int n){
if(n<=0)return 0;
int len=0;
while(n){
digit[++len]=n%10;
n/=10;
}
return dfs(len,0,1,1);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
memset(d,-1,sizeof d);
int T;
cin>>T;
int ans=0;
while(T--){
int l,r;
cin>>l>>r;
ans^=solve(r)-solve(l-1);
}
cout<<ans<<endl;
return 0;
}
牛客 明七暗七
题面:
思路:
很容易想到二分.。
如果按照题目要求进行数位dp统计满足条件的数,有点困难。
所以反过来,统计不满足题目条件的数,n-solve(n)就是满足条件的数了。
d(i,j)表示剩余长度为i,当前模7等于j的方案数。
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=25;
int digit[maxm];
int d[maxm][7];//d[i][j]表示剩余长度为i,当前模7等于j的方案数
int dfs(int len,int sta,int limit){
if(!len)return sta!=0;
if(!limit&&d[len][sta]!=-1){
return d[len][sta];
}
int ma=limit?digit[len]:9;
int ans=0;
for(int i=0;i<=ma;i++){
if(i==7)continue;
ans+=dfs(len-1,(sta*10+i)%7,limit&&i==ma);
}
if(!limit){
d[len][sta]=ans;
}
return ans;
}
int solve(int n){
int len=0;
while(n){
digit[++len]=n%10;
n/=10;
}
return dfs(len,0,1);
}
signed main(){
//统计1-n中满足条件的不好计算
//正难则反,统计1-n中不满足条件的
memset(d,-1,sizeof d);
int m,n;
cin>>m>>n;//m之后的第n个
int l=m,r=1e18;
int ans=-1;
int temp=(m)-solve(m);//1-m中满足的
while(l<=r){
int mid=(l+r)/2;
int cnt=mid-solve(mid)-temp;//1-mid中满足的减去1-(m-1)中满足的
if(cnt>=n){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
cout<<ans<<endl;
return 0;
}
牛客 牛牛的随机数
题面:
思路:
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=70;
const int mod=1e9+7;
int digit[maxm];
int d[maxm][maxm][2];
int ppow(int a,int b,int mod){
a%=mod;
int ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int dfs(int len,int limit,int k,int sta){
//长度,高位限制,第k位,当前第k位的状态
if(!len)return sta;
if(!limit&&d[len][k][sta]!=-1)return d[len][k][sta];
int ma=limit?digit[len]:1;
int ans=0;
for(int i=0;i<=ma;i++){
ans+=dfs(len-1,limit&&i==ma,k,sta||(len==k&&i));
}
if(!limit){
d[len][k][sta]=ans;
}
return ans;
}
int solve(int n,int k){
int len=0;
while(n){
digit[++len]=n%2;
n/=2;
}
return dfs(len,1,k,0);
}
signed main(){
memset(d,-1,sizeof d);
int T;
cin>>T;
while(T--){
int l,r,ll,rr;
cin>>l>>r>>ll>>rr;
int ans=0;
int p=1;
for(int i=1;i<=60;i++){
int cnta=solve(r,i)-solve(l-1,i);
int cntb=solve(rr,i)-solve(ll-1,i);
ans+=(cnta%mod)*((rr-ll+1-cntb)%mod)%mod*p%mod;
ans+=(r-l+1-cnta)%mod*(cntb%mod)%mod*p%mod;
ans%=mod;
p=p*2%mod;
}
ans=ans*(ppow(r-l+1,mod-2,mod)*ppow(rr-ll+1,mod-2,mod)%mod)%mod;
cout<<ans<<endl;
}
return 0;
}
AtCoder Beginner Contest 161 |D - Lunlun Number
题意:
lunlun数定义为任意相邻数字差值小于等于1的数,问第k个lunlun数是多少
思路:
二分+数位dp
code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int digit[25];
int d[25][15][2];
int dfs(int len,int limit,int pre,int last,int ok){
if(!len)return ok;
if(!limit&&!pre&&d[len][last][ok]!=-1)return d[len][last][ok];
int ans=0;
int ma=(limit?digit[len]:9);
for(int i=0;i<=ma;i++){
ans+=dfs(len-1,limit&&i==ma,pre&&i==0,i,ok&&(pre||abs(i-last)<=1));
}
if(!limit&&!pre){
d[len][last][ok]=ans;
}
return ans;
}
int solve(int x){
int len=0;
while(x){
digit[++len]=x%10;
x/=10;
}
return dfs(len,1,1,0,1);
}
int check(int mid){
return solve(mid)-solve(0);
}
signed main(){
memset(d,-1,sizeof d);
int k;
cin>>k;
int l=1,r=1e15;
int ans=-1;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)>=k){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
cout<<ans<<endl;
return 0;
}