2018.12.22【NOIP提高组】模拟B组 JZOJ 2700 数字

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/85205433

大意


A = x × d ( x ) [ A [ L . . R ] ] A=x\times d(x)[A\in[L..R]]


的个数,其中
d ( x ) = x [ x < 10 ] d(x)=x[x<10]
d ( x ) = d ( s ( x ) ) [ x 10 ] d(x)=d(s(x))[x\geq 10]
s ( x ) s(x) x x 各数位之和


思路

直接把洛谷的题解扣过来

首先我们可以想到暴力,由于 D ( x ) D(x) 最终的落点只有 1   9 1~9 ,所以我们可以移项得到 d ( x ) = d ( a / d ( x ) ) d(x)=d(a/d(x)) 的时候, x x 就是一个满足要求的数

于是乎我们得到了下面这个30分的代码:

#include<cstdio>
#include<cctype>
using namespace std;long long f[1000001],L,R;
int t,s[1000001]={0,1,2,3,4,5,6,7,8,9};
inline char Getchar()
{
    static char buf[100000],*p1=buf+100000,*pend=buf+100000;
    if(p1==pend)
	{
        p1=buf; pend=buf+fread(buf,1,100000,stdin);
        if (pend==p1) return -1;
    }
    return *p1++;
}
inline long long read()
{
	char c;int d=1;long long f=0;
	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void write(register long long x)
{
	if(x<0)write(45),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
	return;
}
inline int S(long long x)//暴力算S
{
	if(s[x]) return s[x];
	return s[x]=x%10+S(x/10);
}
inline int D(long long x)//求D
{
	if(x<10) return x;
	return D(S(x));
}
inline bool check(long long x)
{
	for(register int i=1;i<=9;i++)
	if(x%i==0&&D(x/i)==i) return true;//枚举了d(i)后就只需要判断D(x/i)是否合法即可
	return false;
}
signed main()
{
	for(register int i=1;i<=1000000;i++) f[i]=f[i-1]+check(i);//前缀和预处理
	t=read();
	while(t--)
	{
		L=read();R=read();
		write(f[R]-f[L-1]);putchar(10);//输出
	}
}

满分的方法1:首先你得打一个表,然后你发现如果 x x 满足要求则 x + 22680 x+22680 也满足要求,为什么呢?因为 22680 = l c m ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) 22680=lcm(1,2,3,4,5,6,7,8,9)

于是乎,我们只需预处理到22680就可以了,之后的按循环节处理

听大佬说,其实 d ( x ) = ( x 1 )   m o d   9 + 1 d(x)=(x-1)\ mod\ 9+1 具体证明我不会,但是打个表就能发现了嘛,对咯!

方法2: g c d + gcd+ 容斥瞎搞,本蒟蒻不会啊。。。

代码

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;long long f[22681],L,R,maxn;
int t;
inline char Getchar()
{
    static char buf[100000],*p1=buf+100000,*pend=buf+100000;
    if(p1==pend)
	{
        p1=buf; pend=buf+fread(buf,1,100000,stdin);
        if (pend==p1) return -1;
    }
    return *p1++;
}
inline long long read()
{
	char c;int d=1;long long f=0;
	while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline void write(register long long x)
{
	if(x<0)write(45),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+48);
	return;
}
inline int D(long long x){return (x-1)%9+1;}//打了表之后发现的。。。
inline bool check(long long x)
{
	for(register int i=1;i<=9;i++)
	if(x%i==0&&D(x/i)==i) return true;
	return false;
}
inline long long ask(long long x)
{
	return x/22680*f[22680]+f[x%22680];//循环节处理
}
signed main()
{
	for(register int i=1;i<=22680;i++) f[i]=f[i-1]+check(i);
	t=read();
	while(t--)
	{
		L=read();R=read();
		write(ask(R)-ask(L-1));putchar(10);
	}
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/85205433