Shift and Reverse
给出一个长度为n<1e5的序列a
可以进行如下操作任意次:
选择一个位置i
将$a_1,a_2,….a_i,a_{i+1},a_{i+2},..a_n$ 变为
$a_i,a_{i−1},…,a_1,a_n,a_{n−1},…,a_{i+1}$
问能产生多少个不同的序列
对于一个给定序列 如
1 2 3 4 5 6
选择{1 2 3}{4 5 6}
一次操作后得到:3 2 1 6 5 4
选择 {3 2}{1 6 5 4}
再一次操作后得到:2 3 4 5 6 1
选择{2 3 4 5}{6 1}
再一次操作后得到:5 4 3 2 1 6
发现无论如何操作得到的序列一定是
1 2 3 4 5 6 1 2 3 4 5 6 或
6 5 4 3 2 1 6 5 4 3 2 1 的某个长度为n的子段
用hash将子段映射成对应的ull型数
On遍历用map类型的vis标记 统计共有多少中不同的子串
实际上无论几次操作最多得到2n种不同结果
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 38 39 40 41 42 43 44 45 46 47 48 49
| #include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; #define endl '\n' #define Turnoff std::ios::sync_with_stdio(false) #define P pair<ll,ll> const int Max=2e5+5; const int Mod=1e9+7; const int inf=0x3f3f3f3f;
ull Hash[Max],base[Max],num_hash=0; int num[Max],ans=0; map<ull,int>vis; void init(){ base[0]=1; for(int i=1;i<=Max;i++)base[i]=base[i-1]*131; } ull get_hash(int L,int R){ return Hash[R]-Hash[L-1]*base[R-L+1]; } int main(){ Turnoff; int n;init(); while(cin>>n){ vis.clear(); num_hash=0;ans=0; for(int i=0;i<n;i++){ cin>>num[i]; num[i+n]=num[i]; } for(int i=1;i<=2*n;i++)Hash[i]=Hash[i-1]*131+num[i]; for(int i=1;i<=n;i++){ num_hash=get_hash(i,i+n-1); if(!vis[num_hash])ans++; vis[num_hash]=1; } reverse(num,num+n*2); for(int i=1;i<=2*n;i++)Hash[i]=Hash[i-1]*131+num[i]; for(int i=1;i<=n;i++){ num_hash=get_hash(i,i+n-1); if(!vis[num_hash])ans++; vis[num_hash]=1; } cout<<ans<<endl; } }
|