思路
众所周知,当拿到一道题但是不会做的时候,可以考虑随机化。
首先,我们用 vector 记录每种颜色在那些位置出现过,每次在区间里随机一个位置,看这个位置对应的颜色在此区间内是否出现大于长度除以二。这样进行大概 20 20 20 次,一交,竟然对了!
后来想了想,确实能对。这种算法会错当且仅当存在答案但没随机到。如果存在答案,那么随机一次没随机到的概率就是 1 2 \frac 1 2 21,随机 k k k 次都没随机到的概率是 1 2 k \frac 1 {2^k} 2k1。随机 20 20 20 次出错的概率大约是 1 1 0 6 \frac 1 {10^6} 1061,而询问只有 1 0 5 10^5 105 组。只要不是运气极差,就能轻松 AC。
什么,你说你瞧不起没有正确性保证的算法?那你以后就不要用哈希了!
代码
#include <bits/stdc++.h>
using namespace std;
template<typename T> inline void read(T &x)
{
x = 0;
T f = 1;char ch = getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
{
f = -1,ch = getchar();
break;
}
ch = getchar();
}
while(ch>='0'&&ch<='9')
x = (x<<3)+(x<<1)+ch-48,ch = getchar();
x*=f;
}
template<typename T> inline T read()
{
T x;read(x);return x;
}
template<typename T> void write(T x)
{
if(x<0) x = -x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+48);
}
template<typename T> inline void writen(T x)
{
write(x);
putchar(10);
}
const int N = 3e5+5;
int n,c,q,a[N];
vector<int> v[N];
inline void solve()
{
int l,r;
read(l),read(r);
for(int _ = 1;_<=20;_++)//随机 20 次
{
int p = l+rand()%(r-l+1);
int res = upper_bound(v[a[p]].begin(),v[a[p]].end(),r)-lower_bound(v[a[p]].begin(),v[a[p]].end(),l);//确定个数
if(res>(r-l+1)/2) return putchar('y'),putchar('e'),putchar('s'),putchar(32),writen(a[p]);
}
puts("no");
}
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
srand(time(0));
read(n),read(c);
for(int i = 1;i<=n;i++)
read(a[i]),v[a[i]].push_back(i);
for(int i = 1;i<=c;i++)
v[i].push_back(n+1);
read(q);
while(q--) solve();
return 0;
}
后记
双倍经验,虽然是个蓝题。