明七暗七
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
今天是个特殊的日子,CSL和他的小伙伴们围坐在一张桌子上玩起了明七暗七的游戏。游戏规则是这样的:

一个人报出一个起始数,接下来按照逆时针的顺序轮流报数,如果碰到数是7的倍数或含有7,则拍手,下一个人接着报数。直到有一个人报错了数字或者没有及时拍手为止。

玩游戏嘛,当然得有惩罚。这么简单的游戏对CSL的学霸小伙伴而言实在是太无脑了,轻轻松松数到上万根本不在话下。但是对于数学是体育老师教的CSL来说,实在是太难了。快帮他算算什么时候应该拍手吧。

输入描述:
输入两个整数m和n。(1 ≤ m, n ≤ 1012)
输出描述:
输出一个整数,表示m以后第n个需要拍手的数字。

#include<cstdio> 
#include<cstring>
using namespace std;

typedef long long ll;

ll dp[20][8];
int digit[25];

ll dfs(int deep,ll state,bool lmt){
   if (!deep) return state?1:0;
   if (!lmt&&dp[deep][state]>=0) return dp[deep][state];
   int i,up=lmt?digit[deep]:9;
   ll cnt=0;
   for (i=0;i<=up;i++)
    {
    	if (i==7) continue;
    	cnt+=dfs(deep-1,(state*10+i)%7,lmt&&i==up);
	}
	return lmt?cnt:dp[deep][state]=cnt;
}

ll cal(ll num){
	int k=1;
	while (num){
		digit[k++]=num%10;
		num/=10;
	}
	return dfs(k-1,0,true);
} 

int main(){
	ll n,m,left,right,mid,tmp;
	
    while (~scanf("%lld%lld",&m,&n)){
    	memset(dp,-1,sizeof(dp));
    	left=0;right=1LL*1e18;
			
    	tmp=m-cal(m);
		while (left<=right){
			mid=(left+right)>>1;
			if (mid-cal(mid)>=tmp+n) 
			  right=mid-1;
			else 
			  left=mid+1;
		}
		printf("%lld\n",left); 
	}
	return 0;
}
好朋友
时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld
题目描述 
BLUESKY007有很多关系很好的朋友,他们无一例外,名字均由数字组成(首字符不为0)且含有"007"(例如“10007”,“10707”就是她的好朋友,而“97037”,“70709”不是),即对于字符串s存在i,j,k(i< j< k)满足
¯¯¯¯¯¯¯¯¯¯¯¯¯
s
i
s
j
s
k
=
¯¯¯¯¯¯¯¯
007
sisjsk¯=007¯. 
虽然BLUESKY007眼力极佳,一眼就能看出一个人是不是自己的好朋友,但BLUESKY007是个蒟蒻,她并不擅长数数,但她又想知道在[li,ri]内有多少人是自己的好朋友,所以就找到了你来帮忙. 
她会向你询问t次,由于询问次数可能很多,所以你只需要告诉她t次询问答案的异或和即可.
输入描述:
第一行一个整数t,表示询问个数 
接下来t行,每行两个整数li,ri
输出描述:
一行一个整数表示答案
#include<cstdio>
#include<iostream>
#include<cstring>
#define lint long long
using namespace std;
lint t,l,s,ch,r,ans,arr[20],res[20][4];
inline lint read(){
	s=0,ch=getchar();
	while (ch==' '||ch=='\n') ch=getchar();
	while ('0'<=ch&&ch<='9')
	   s=s*10+ch-'0',
	   ch=getchar();
	return s;
}

lint dfs(lint pos,lint cmd,lint led,lint lim){
	if (pos==0)  return cmd==3;
	if (!led&&!lim&&res[pos][cmd])
	   return res[pos][cmd];
   
    lint maxn=lim?arr[pos]:9,tmp=0;
    for (lint i=0;i<=maxn;++i){
    	if (cmd==0)
    	  tmp+=dfs(pos-1,!i&!led,led&!i,lim&(i==arr[pos]));
    	else if (cmd==1)
		  tmp+=dfs(pos-1,(i==0)+1,0,lim&(i==arr[pos]));
		else if (cmd==2)
		  tmp+=dfs(pos-1,(i==7)+2,0,lim&(i==arr[pos]));
		else if (cmd==3)
		  tmp+=dfs(pos-1,3,0,lim&(i==arr[pos])); 
	}
	if (!led&&!lim) res[pos][cmd]=tmp;
	return tmp;
} 

inline lint sol(lint x){
	memset(arr,0,sizeof(arr));
	memset(res,0,sizeof(res));
	lint cnt=0;
	while (x!=0){
		arr[++cnt]=x%10;
		x/=10;
	}
	return dfs(cnt,0,1,1);
}

int main(){
	t=read();
	while (t--){
	  l=read(),r=read();
	  ans^=(sol(r)-sol(l-1));
	}
   printf("%lld\n",ans);
}


[AHOI2009]SELF 同类分布
时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述 
给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。
输入描述:
输入a,b
输出描述:
输出[a,b]中各位数字之和能整除原数的数的个数
示例1
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#define N 203
#define LL long long

using namespace std;
LL f[21][N][N][2],l,r;
int cnt,a[N];

LL solve(LL x){
	if (x==0) return 0;
	cnt=0;
	while (x){
		a[++cnt]=x%10;
		x/=10;
	}
	reverse(a+1,a+cnt+1);
	LL ans=0;
	for (int sum=1;sum<=18*9;sum++){
		 memset(f,0,sizeof(f));
		 f[0][0][0][1]=1;
	
	     for(int i=0;i<=cnt;i++)
		  for (int j=0;j<=18*9;j++)
		   for (int k=0;k<=18*9;k++)
		    for (int l=0;l<=1;l++)
			  if (f[i][j][k][l]){
			  	for (int t=0;t<=9;t++){
			  		if (l==1&&t>a[i+1]) break;
			  		f[i+1][j+t][(k*10+t)%sum][(l==1&&t==a[i+1])?1:0]+=f[i][j][k][l];
				  }
			  	
			  } 
		ans+=f[cnt][sum][0][0]+f[cnt][sum][0][1];
	}
	return ans;
}



int main(){ 
  scanf("%lld%lld",&l,&r);
  printf("%lld\n",solve(r)-solve(l-1));
}
链接:https://ac.nowcoder.com/acm/problem/19945
来源:牛客网

[CQOI2016]手机号码
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述 
人们选择手机号码时都希望号码好记、吉利。比如号码中含有几位相邻的相同数字、不含谐音不吉利的数字等。手机运营商在发行新号码时也会考虑这些因素,从号段中选取含有某些特征的号 码单独出售。为了便于前期规划,运营商希望开发一个工具来自动统计号段中满足特征的号码数 量。
工具需要检测的号码特征有两个:号码中要出现至少3个相邻的相同数字,号码中不能同时出现8和4。号码必须同时包含两个特征才满足条件。满足条件的号码例如:13000988721、 23333333333、14444101000。而不满足条件的号码例如:1015400080、10010012022。 手机号码一定是11位数,前不含前导的0。工具接收两个数L和R,自动统计出[L,R]区间 内所有满足条件的号码数量。L和R也是11位的手机号码。
输入描述:
输入文件内容只有一行,为空格分隔的2个正整数L,R。
10^10 ≤  L ≤  R < 10^11
输出描述:
输出文件内容只有一行,为1个整数,表示满足条件的手机号数量。
#include<cstdio>
#include<cstring>
#include<string>
#define LL long long
using namespace std;

LL L,R,A[20],B[20],f[20][20][20][2][2][2][2][2],ans;

int main(){
	scanf("%lld%lld",&L,&R);
	for (int i=11;i>=1;--i)
	{A[i]=L%10,L/=10;
	 B[i]=R%10,R/=10;
	}
	for(int i=A[1];i<=B[1];i++)
	  f[1][i][1][0][i==4?1:0][i==8?1:0][i==A[1]?1:0][i==B[1]?1:0]=1;
	
	for (int i=1;i<=10;++i)
	  for (int j=0;j<=9;++j)
	   for (int k=1;k<=11;k++)
	     for (int p=0;p<=1;++p)
	       for (int a=0;a<=1;a++)
	        for (int b=0;b<=1;b++)
			 for (int c=0;c<=1;c++)
			  for (int d=0;d<=1;d++)
			     if (f[i][j][k][p][a][b][c][d]){
			     	 int l,r;
			     	 if (c&&d) l=A[i+1],r=B[i+1];
			     	 else  if (!c&&!d) l=0,r=9;
			     	 else if (!c) l=0,r=B[i+1];
			     	 else l=A[i+1],r=9;
			     	 for (int t=l;t<=r;t++){
			     	 	int x=(j==t)?k+1:1;
			     	 	f[i+1][t][x][p|(x>=3?1:0)][a|(t==4?1:0)][b|(t==8?1:0)][c&(t==A[i+1]?1:0)][d&(t==B[i+1]?1:0)]+=f[i][j][k][p][a][b][c][d];
					  }
				 } 
				 
	for (int j=0;j<=9;j++)
	 for (int k=1;k<=12;k++)
	   for (int c=0;c<=1;c++)
	     for (int d=0;d<=1;d++)
		   ans+=f[11][j][k][1][0][1][c][d]+f[11][j][k][1][1][0][c][d]+f[11][j][k][1][0][0][c][d]; 
	printf("%lld\n",ans);	 
}