Codeforces Round #707 DIV.2 C 1500A Going Home(暴力,鸽巢定理)
题目大意:
给定长度为 n 的序列 a,求出任意一组 x,y,z,w 满足:
- x,y,z,w 互不相同;
- ax+ay=az+aw;
如果有解,输出一行 YES 后输出任意一组解;否则输出一行 NO。
本题有两个思路。基本都是暴力。
思路一:
转化为差分数组。由ax+ay=az+aw可化为ax-az=aw-ay
可以转换为存在两组数,他们的差值相同。如果没有两对数的差相等,那么其排序后相邻2数之间的差值也不相同。
最坏的情况即1,2,4,7,11,16,22……这样差值从1~n.故最长长度为4e3,当超过4e3时,则遍历每一组相邻的差值,找到对应差值相同的点的下标即可。
而像这样1,2,3,5,7,10,13,17,21,26这样的相邻差值相同,但是是三个连在一起的是没法通过相邻差值相同来得到答案的,只能通过暴力的方法来找到解:3,7,13,17.
由于an不大于2.5e6,故如果串的长度大于4e3相邻差值相同且能直接通过相邻差值得到答案。
所以对于大于4e3长度的串,我们只需要排序后计算相同的相邻差值,且保证不同下标大于3个即可。
对于小于4e3长度的串,我们则只能暴力遍历所有的差值,找到2个由4个不同下标得到的差值即可。(由于长度不大于4e3,故暴力的时间也不会超过时限)
思路二:
枚举ai+aj的值并记录,如果该值出现了第二次且四个下标各不相同则为答案。
由于an小于2.5e6通过鸽巢定理,所以ai+aj的值一定会小于5e6。
即设ai+aj的值为s。根据鸽巢定理可知:当s取了5e6+1次时,肯定会有2个值相同。即最多需要遍历5e6次即能找出答案。
但是由于可能会出现5,6,5这样两个相同的情况,或者5,5,5,6这样的情况。故最多可能需要s出现4次才能找到答案。
但这也无关紧要,因为最坏情况下最多遍历5e6*4=2e7次也必定可以得到答案。
然后就能自动退出。
因此一定能满足时间要求。
故直接暴力即可。
AC代码如下:
#include<cstdio> #include<cctype> #include<algorithm> #include<cstring> #define MAXN 5000005 #define MAXM 200005 using namespace std; typedef long long ll; typedef pair<int,int> pii; int n; struct node{ int x,y; }ans[MAXN],a[MAXM];//ans中的x,y分别表示组成答案的两个值的下标。a的x表示值,y表示该值的下标 int cmp(const node &a,const node &b){ return a.x<b.x; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i].x); a[i].y=i; } sort(a+1,a+n+1,cmp);//排序后处理更快,也可以不排,不知道为什么不排序时间差了200ms for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++){ int s=a[i].x+a[j].x; if(!ans[s].x){ ans[s].x=a[i].y,ans[s].y=a[j].y; }else if(ans[s].x!=a[i].y&&ans[s].y!=a[i].y&&ans[s].x!=a[j].y&&ans[s].y!=a[j].y){ printf("YES\n%d %d %d %d",a[i].y,a[j].y,ans[s].x,ans[s].y); return 0; } } printf("NO"); return 0; }

浙公网安备 33010602011771号