首页 > 代码库 > Codeforces 354C. Vasya and Beautiful Arrays【DP,暴力】
Codeforces 354C. Vasya and Beautiful Arrays【DP,暴力】
题目大意:
有一组数,你可以对每一个数做减法,减去的数不超过k,问最后你最大能得到的整个数组的GCD是多少
做法:
最后要求的是GCD(假设为g),那么也就是说,对于数组中的数a[i]来说,减去某个不大于k的值之后,就能被g整除;换句话说,a[i]%g<=k,只要满足该条件即可.
首先,由于只能对数进行减法操作,假设m为数组a中的最小值,ma为最大值;那么答案一定不会超过m,也就是说,答案的上界是m。
再观察上面得出的公式:a[i]%g<=k,如果g<=k+1,那么该公式是无论如何都满足的(因为a[i]%g,结果一定在0~g-1之间。)。也就是说,g的下界是k+1。
那么这样的话,是不是就说明我们可以暴力枚举k+1~m之间的数一个个的检查是否是正确答案呢?
答案为YES!
我们要求最大值,那当然是从大到小枚举,一旦找到答案,就输出,结束。
现在大体思路确定,解决剩下的小问题:我们应该怎么判断一个枚举的数是不是正确答案呢?
如果这个当前的g是正确答案,那么就是说,a数组中的每个数减去一个不大于k的值之后,变成了g的倍数(模g为0);也就是说,每个数都存在于[i*g,i*g+k](1<=i<=ma/g)这样的区间之间!那么我们只需要判断在这样的区间内的个数是否等于总的数的个数,如果相等,那就是正确答案,如果不等,那么继续枚举下一个答案。
那我们现在想想复杂度的问题,枚举过程中,最大循环次数应该是这样,n/1+n/2+n/3+......+n/n=N*logN(调和级数)复杂度也在允许范围内~
当然,当上界m小于下界k+1时,由于0~k+1的数一定是满足条件的,而答案又不能超过m,那毫无疑问,正确答案一定为m。
代码:
#include <iostream> #include <cstdio> #define N 1000010 using namespace std; int a[N/3]; int sum[N*2]; int n,k,m,ma,ans; bool running(int Ans) { int limit=ma/Ans; int ret=0; for(int i=1;i<=limit;i++) ret+=(sum[i*Ans+k]-sum[i*Ans-1]); return ret==n; } int main() { scanf("%d%d",&n,&k); m=11111111; for(int i=0;i<n;i++) { scanf("%d",a+i); sum[a[i]]++; m=min(m,a[i]); ma=max(ma,a[i]); } for(int i=m;i<=ma+k;i++){ sum[i]+=sum[i-1];//求前缀和,判断某个区间内有多少个数 //cout<<i<<": "<<sum[i]<<endl; } if(m<=k+1) {cout<<m<<endl;return 0;} for(ans=m;ans>=k+1;ans--) { if(running(ans)) { cout<<ans<<endl; return 0; } } return 0; }
Codeforces 354C. Vasya and Beautiful Arrays【DP,暴力】
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。