1. 程式人生 > >2018.12.22【NOIP提高組】模擬B組 JZOJ 2700 數字

2018.12.22【NOIP提高組】模擬B組 JZOJ 2700 數字

大意


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);
	}
}