这个题目也算折磨了我一下午了。
解决问题关键在于Yi + Yj <= L 。这说明序列Y中至多有1个数字可以大于等于L/2,否则两者之和将大于L。而序列X中任意小于等于L/2都可以放进序列Y中,而大于等于L/2的至多有一个。
如果有的话,那么一定是X中大于等于L/2那些序列里面最小的那一个。只要这个最小的与Y序列(即X中小于等于L/2的序列)最大的那个之和小于等于L,就能够把这个最小的放进Y中。
这里有个地方要注意,当 mod<=L/2 ,所得X必定都是小于L/2的,所以直接输出n就可以了。否则将会超时。
我一开始想按常规思路开个数组把序列存起来,但是2*107 如此之大的数据量存下并不方便。而且循环嵌套容易超时。于是我想到了序列X的周期性。。。但是依旧很麻烦。最后还是放弃了问了别人。
但是还是一直都错。
第一个问题是关于MAX,MIN的初始值的处理上,开始的时候我定义它们为int,分别取值MAX=-2147483648,MIN=2147483647,这是int的上下界。但是问题也因此出现,当MIN没有被覆盖(当然MAX被覆盖了),运行到mn+mx<=L这句就会发生溢出的问题,悲剧。
开始数据类型全用int,用一组极大的数据【20000000 2000000000 1000000000 1000000000 1999999999】,我依次输出所得每个x,发现全部溢出,于是改用long long。但是A,B,mod等还是int,得到结果还是溢出,我数据类型转换方面学的并不精通,所以干脆所有数据都换成long long 。奇怪的是将A,B等定义在main中会出现错误结果,改为全局变量于是AC。
查了一下。
使用全局变量程序运行时速度更快一些(因为内存不需要再分配),不过在计算机配置很高的今天,也快不了多少。
学的还是不到家,有人scanf输入用%I64d即使存局部变量也不会出现我有的问题。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<algorithm> using namespace std; long long n,L,A,B,mod; int main() { //freopen("in.txt","r",stdin); while(scanf("%lld %lld %lld %lld %lld",&n,&L,&A,&B,&mod)!=EOF) { if(mod<=L/2) { printf("%d\n",n); continue; } int count=0; long long mn=L+1,mx=-1; for(int i=1;i<=n;++i) { long long res=((A*i)+B)%mod; if(res<=L/2) { count++; if(res>mx) mx=res; } else { if(res<mn) mn=res; } } if(mn<=L&&mn+mx<=L)count++; printf("%d\n",count); } return 0; }
研究了一下数据类型转换,如果是 long long = int *int ,int*int将得到int类型再转为longlong,可能有精度损失,可以使用强制转换,将两个int都强转为longlong再相乘。