牛客暑期营1F Solution

题目链接

题解

可以发现,只有\(\le 3\)位数才会出现非3友好的情况。证明:如果前\(i\)个数模\(3=\)\(i+1\)个数模\(3\),则说明第\(i+1\)个数可以被\(3\)整除。因此非3友好数的所有前缀模\(3\)一定不相等,根据鸽巢原理可得上述结论。

打表即可,以下代码为TLE的数位dp修改而来(。﹏。*)

AC代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
int a[20],b[20][1050],c[20],n;
int dfs(int pos,bool ok,int sta,bool lim,bool zr)
{
	if(!pos) return ok;
	if(!lim && !zr && (!ok && b[pos][sta]!=-1)) return b[pos][sta];
	if(!lim && !zr && (ok && c[pos]!=-1)) return c[pos];
	int up=lim?a[pos]:9,ans=0,tmp;
	if(ok)
	{
		for(int i=0;i<=up;i++) ans+=dfs(pos-1,ok,sta,lim && i==up,zr && !i);
		if(!lim && !zr) c[pos]=ans;
		return ans;
	}
	bool num[11];
	memset(num,0,sizeof(num));
	int qwq=sta;
	for(int i=0;sta;i++) num[i]=(sta&1),sta>>=1;
	num[0]=num[3]=num[6]=num[9]=1;
	for(int i=0;i<=up;i++)
	{
		if(num[i] && (!zr || i)) ans+=dfs(pos-1,1,sta,lim && i==up,zr && !i);
		else
		{
			tmp=0;
			for(int j=i+1;j<=9;j++)
				if(num[j]) tmp|=(1<<(j-i));
			for(int j=3;j<=18;j+=3)
				if(j>i && j-i<=9) tmp|=(1<<(j-i));
			if(i%3==0) tmp|=1;
			ans+=dfs(pos-1,ok,tmp,lim && i==up,zr && !i);
		}
	}
	if(!lim && !zr) b[pos][sta]=ans;
	return ans;
}
int sol(int x)
{
	n=0;
	while(x) {a[++n]=x%10; x/=10;}
	int tmp=(1<<3)+(1<<6)+(1<<9)+1;
	return dfs(n,0,tmp,1,1); 
}
signed main()
{
	memset(b,-1,sizeof(b));
	memset(c,-1,sizeof(c));
	int t,l,r,ans;
	scanf("%lld",&t);
	while(t--) 
	{
		scanf("%lld%lld",&l,&r); ans=0; 
		if(l<100) ans=sol(min(100ll,r))-sol(l-1);
		else ans=1;
		printf("%lld\n",ans+max(0ll,r-max(100ll,l)));
	}
	return 0;
}
posted @ 2021-07-20 12:46  violet_holmes  阅读(25)  评论(0编辑  收藏  举报