描述
给了你一个数字串,问你[l,r]之间有没有数字[1,r-l+1]的一个排列。
思路
hash 随机数法
这个办法是看题解得来的,思考了很长时间,才大致弄明白。
以下几点需要特别注意
- srand(time(NULL))时间作为随机数的种子
- rand()返回0-32767之间的一个数,这个32767是16bit即两个字节的,无符号int类型的最大值,那么可以理解RANDuLL()函数。
- 用亦或表示区间很方便
- XOR[i]中表示[1~i]的亦或值,sum[i]表示a[1]~a[i]的亦或值。这个是想类似于前缀求法
AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #include <time.h> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 1000010 #define uLL unsigned long long uLL XOR[maxn],a[maxn],sum[maxn]; inline uLL RANDuLL() { uLL tmp=(rand()+rand())*((uLL)1<<47)+(rand()+rand())*((uLL)1<<31)+(rand()+rand())*((uLL)1<<15)+(rand()+rand()); return tmp; } int main() { srand(time(NULL)); XOR[0]=0; sum[0]=0; for(int i=1; i<maxn; i++){ a[i]=RANDuLL(); XOR[i]=XOR[i-1]^a[i]; } int n,m,l,r,tmp; while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1; i<=n; i++){ scanf("%d",&tmp); sum[i]=a[tmp]^sum[i-1]; } while(m--){ scanf("%d%d",&l,&r); if(XOR[r-l+1]==(sum[r]^sum[l-1])) puts("YES"); else puts("NO"); } } }
|