https://loj.ac/problem/2427 题目描述 给出一段序列A,求一个k使将序列A分为k段(不是倍数最后一段舍去)不同的段数最多。一个串的反转和它本身相同。 思路 这道题A的长度并不大,我们可
https://loj.ac/problem/2427
题目描述
给出一段序列A,求一个k使将序列A分为k段(不是倍数最后一段舍去)不同的段数最多。一个串的反转和它本身相同。
思路
这道题A的长度并不大,我们可以暴力枚举k,对于每个k计算不同串的数目,再更新答案。需要注意这里并没有说一个串与它的顺序无关,二只是与它的反转有关,我们只要正反处理两次Hash值即可。不过这道题有点卡单Hash,最好用双Hash,不过我懒得写了,调一调b就A了。
代码
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ull; const ull p=10000019; const ull MAXN=2e5+10; ull sum1[MAXN],sum2[MAXN],power[MAXN],ans[MAXN],n,a[MAXN]; ull f_hash(ull l,ull r,bool f) { if(f)return sum1[r]-sum1[l-1]*power[r-l+1]; else return sum2[l]-sum2[r+1]*power[r-l+1]; } set<ull>s; ull cal(int k) { s.clear(); for(int i=1;i+k-1<=n;i+=k) { ull tmp=min(f_hash(i,i+k-1,1),f_hash(i,i+k-1,0)); s.insert(tmp); } return s.size(); } int main() { scanf("%llu",&n); for(ull i=1;i<=n;i++) scanf("%llu",&a[i]); power[0]=1; for(ull i=1;i<=n;i++) { sum1[i]=sum1[i-1]*p+a[i]; power[i]=power[i-1]*p; } for(ull i=n;i>=1;i--) sum2[i]=sum2[i+1]*p+a[i]; // for(ull i=1;i<=n;i++) // printf("%llu %llu\n",sum1[i],sum2[i]); ull maxx=0,cnt=0; for(ull i=1;i<=n;i++) { ull now=cal(i); if(now>maxx) { maxx=now; cnt=0; } if(maxx==now) ans[++cnt]=i; } printf("%llu %llu\n",maxx,cnt); for(int i=1;i<=cnt;i++) printf("%llu ",ans[i]); return 0; }