Codeforces Round #707 DIV.2 C 1500A Going Home(暴力,鸽巢定理)

题目大意:

给定长度为 n 的序列 a,求出任意一组 x,y,z,w 满足:

  1. x,y,z,w 互不相同;
  2. 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;
}

 

posted @ 2021-03-17 17:13  mikku  阅读(99)  评论(0)    收藏  举报