[JZOJ2700] 【GDKOI2012模拟02.01】数字

题目

在这里插入图片描述

题目大意

其实这题的题目大意非常简练,所以我认为我不用解释了。


思考历程

首先乱推了一波,然后什么东西都没有发现。
于是想想 D ( i ) D(i) D(i)的性质。
我发现,由于每次是将各位上的数字相加。所以最多操作三次。
本来是一个很大的数,然后缩小成百位数,然后缩成十位数,最后缩成个位数。
我想,既然缩小一次就成了百位数了,所以,为什么不直接把百位数的表打出来,然后再继续推式子呢?
然后我就把表打了出来。
于是我就发现,我前面的想法尽是没用的……
因为我发现了一个显而易见的规律: D ( i ) = ( i − 1 ) m o d    9 + 1 D(i)=(i-1) \mod 9+1 D(i)=(i1)mod9+1
这个规律可以感性理解,也可以理性证明,反正很简单,我就不说了。
所以说,一个“被喜欢的数”就是能被 x ∗ ( ( x − 1 ) m o d    9 + 1 ) x*((x-1)\mod 9+1) x((x1)mod9+1)表示的数。
接下来就开始了我的瞎搞历程(提醒一下,正确性有误……)
由于 D ( x ) &lt; = 9 D(x)&lt;=9 D(x)<=9,不妨枚举 D ( x ) D(x) D(x),设为 j j j
设现在的数为 i i i。显然,如果要成立,首先要满足 i m o d &ThinSpace;&ThinSpace; j = 0 i \mod j=0 imodj=0
然后乱推: ( i j − 1 ) m o d &ThinSpace;&ThinSpace; 9 + 1 = j \left(\frac{i}{j}-1\right) \mod 9+1 =j (ji1)mod9+1=j
所以 ( i j − 1 ) m o d &ThinSpace;&ThinSpace; 9 = j − 1 \left(\frac{i}{j}-1\right) \mod 9=j-1 (ji1)mod9=j1
由于 j − 1 &lt; 9 j-1&lt; 9 j1<9,所以 i j − 1 ≡ j − 1 ( m o d &ThinSpace;&ThinSpace; 9 ) \frac{i}{j}-1 \equiv j-1 (\mod 9) ji1j1(mod9),所以 i j ≡ j ( m o d &ThinSpace;&ThinSpace; 9 ) \frac{i}{j} \equiv j (\mod 9) jij(mod9)
然后就是最尴尬的步骤: i ≡ j 2 ( m o d &ThinSpace;&ThinSpace; 9 ) i\equiv j^2(\mod 9) ij2(mod9)
所以说,如果 i i i满足条件,必定有一个 j j j使得 i m o d &ThinSpace;&ThinSpace; j = 0 i \mod j=0 imodj=0 i ≡ j 2 ( m o d &ThinSpace;&ThinSpace; 9 ) i\equiv j^2(\mod 9) ij2(mod9)
哈,这东西好像可以DP!
f i , j , k f_{i,j,k} fi,j,k表示到第 i i i位,模 2520 2520 2520的余数为 j j j,第 i i i位上的值为 k k k的数的个数。
2520 2520 2520 1 1 1 9 9 9的最小公倍数)
按照之前推出来的条件,我们可以发现它是否为“被喜欢的数”只和 j j j有关。
那我就可以愉快地数位DP了。

然而现实是残酷的……
WA了……
后来推了好久,我发现原来是上面的一步出现了问题:
我们知道 i j ≡ j ( m o d &ThinSpace;&ThinSpace; 9 ) \frac{i}{j} \equiv j (\mod 9) jij(mod9),可以推出 i ≡ j 2 ( m o d &ThinSpace;&ThinSpace; 9 ) i\equiv j^2(\mod 9) ij2(mod9)。可是后者不一定推出前者。
因为 9 9 9不是质数……
不过如果只有这点错误,随便改一改那似乎也是可以过得去的。
然后我就发现原来还是需要判重!
怎么判?数位DP怎么判?判不了啊!

XC说,今天除了第一题之外,其他的题还是很有难度的。
除了第一题!!!!!!


正解

先说一个别人家的正解(当然我不懂是为什么):
就是打一波表,然后发现,咦,原来是有循环节的!
然后就随随便便的搞定了……

然后再说一个正经一些的做法:
首先对于一个数 x ∗ D ( x ) x*D(x) xD(x),我们可以将其表示为 ( 9 t + D ( x ) ) ∗ D ( x ) (9t+D(x))*D(x) (9t+D(x))D(x)
D ( x ) D(x) D(x)的取值是很少的,也就只有 9 9 9种。
我们把它当成常数来看,然后就变成 9 D ( x ) ∗ t + D 2 ( x ) 9D(x)*t+D^2(x) 9D(x)t+D2(x),变成 a t + b at+b at+b的形式。
对于一个 D ( x ) D(x) D(x),我们可以很容易地计算出它在某一个区间里的贡献。
然后我们要去重。
如何去重?容斥原理,将一些式子合并一下就可以了。用扩展中国剩余定理就好。
可以手打扩展中国剩余定理,其实也是可以推出来的嘛……
可是某些机智懒惰的同学发现了一个好方法:
我们将所有的 D ( x ) D(x) D(x)的式子列出来,然后将它们都模 9 9 9
然后就会惊奇地发现下面的这张表:
1 4 0 7 7 0 4 1 0
只有模数相同的有可能可以合并。
所以运算量大大减少……
然后我就全部手推出来了。具体见程序(有的式子合并之后无解,我也有注释)。
然后这题就愉快地解决了。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
struct func{
	int a,b,ty;
} d[20];
int cnt;
inline long long getans(long long lim){
	long long res=0;
	for (int i=1;i<=cnt;++i)
		if (lim-d[i].b>=0)
			res+=((lim-d[i].b)/d[i].a+1)*d[i].ty;//计算贡献……不用解释
	return res;
}
int main(){
	for (int i=1;i<=9;++i)
		d[++cnt]={i*9,i*i,1};
	d[++cnt]={72,64,-1};//d[1] and d[8]
	d[++cnt]={126,112,-1};//d[2] and d[7]
	d[++cnt]={180,160,-1};//d[4] and d[5]
	d[++cnt]={54,36,-1};//d[3] and d[6] 其实在仔细观察之后可以发现,这个和d[6]抵消了。
	//d[3] and d[9]=empty
	//d[6] and d[9]=empty
	//d[3] and d[6] and d[9]=empty
	int T;
	scanf("%d",&T);
	while (T--){
		long long l,r;
		scanf("%lld%lld",&l,&r);
		printf("%lld\n",getans(r)-getans(l-1));
	}
	return 0;
}

总结

每次做比赛时,我要么是不屑于打表,要么就是懒得打表。
可是经验和事实告诉我们,打表是信息学竞赛选手必备的技能!
我们要培养起自己的打表精神,让它贯彻入信息学竞赛中!
瞎BB结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值