记一个CF的坑---unordered_set

题目链接:https://codeforces.com/problemset/problem/1656/B
思路:
对序列 \(a\) : \(\{a_1,a_2,\cdots , a_n\}\) , 可进行如下操作:
\(select\ x,\ erase(a_x)\ and\ set\ a_i\ to\ a_i-a_x\)
问是否可以通过 \(n-1\) 次操作使序列 \(a\) 中剩余元素等于给定元素 \(k\)
解法:
换一种理解 , 是否存在 \(a\) 的一种排列 , 使得依次删除序列 \(a\) 中前 \(n-1\) 个元素后 , \(a_n=k\) .前三次操作的结果如下:

  • \(\{a_2-a_1,a_3-a_1,a_4-a_1,\cdots,a_n-a_1\}\)
  • \(\{a_3-a_2,a_4-a_2,a_5-a_2,\cdots,a_n-a_2\}\)
  • \(\{a_4-a_3,a_5-a_3,a_6-a_3,\cdots,a_n-a_3\}\)

可见经过 \(n-1\) 次操作后 , 序列中剩余元素为 \(a_n-a_{n-1}\) , 故原题等价于序列 \(a\) 中是否存在\(i,j\) , 使得\(|a_i-a_j|=k\).故我们只需要遍历一遍数组 \(a\) ,判断数组中是否存在\(a_i-k\) , 若存在则必定可以获得 \(k\) , 否则无法获得 \(k\) , 于是便有了如下代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
 
int t,n,k,a;
unordered_set<int> mp;
 
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>t;
    while(t--){
        cin>>n>>k;
        mp.clear();
        for(int i=1;i<=n;i++){
            cin>>a;
            mp.insert(a);
        }
        bool flag = 1;
        for(auto i=mp.begin();i!=mp.end();i++){
            if(mp.count(*i-k)>0){
                flag = 0;
                break;
            }
        }
        cout<<(flag==1?"NO":"YES")<<'\n';
    }
    
    return 0;
}
于是便自信满满的提交了它, TLE 23 ???

直到我发现了如下文章:https://zhuanlan.zhihu.com/p/399073979?ivk_sa=1024320u
哈 ? 还有这种操作 ?

更改后的代码如下:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
 
int t,n,k,a;
unordered_set<int> mp;
 
signed main(){
    int p = rand();
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>t;
    while(t--){
        cin>>n>>k;
        mp.clear();
        for(int i=1;i<=n;i++){
            cin>>a;
            mp.insert(a^p);
        }
        bool flag = 1;
        for(auto i=mp.begin();i!=mp.end();i++){
            if(mp.count((((*i)^p)-k)^p)>0){
                flag = 0;
                break;
            }
        }
        cout<<(flag==1?"NO":"YES")<<'\n';
    }
    
    return 0;
}
posted @ 2022-03-25 14:23  SCat123  阅读(42)  评论(0)    收藏  举报