CodeForces - 722F Cyclic Cipher(数论)
题目大意
有n个循环无穷序列,第i个序列 a i a_i ai的循环周期为 k i k_i ki,每个序列的第一项 a i , 1 a_{i,1} ai,1到第k项 a i , k i a_{i,k_i} ai,ki为给定的数字.对于每种可能的元素取值,找到一个小标j,找到 j j j使得 j ≤ 1 0 100 j\le10^{100} j≤10100且序列 a 1 , j , a 2 , j , . . . a n , j {a_{1,j},a_{2,j},...a_{n,j}} a1,j,a2,j,...an,j中有着最长连续的v,问对于每个v输出最长长度
解题思路
首先明确一个问题,两个序列中的两个相同的数字何时会有相同的位置?
首先我们假设有两个序列
a
i
,
a
i
+
1
a_i,a_{i+1}
ai,ai+1都有某个数v,其在
a
i
a_i
ai中第一次出现在
x
i
x_i
xi位,在
a
i
+
1
a_{i+1}
ai+1中第一次出现在
x
i
+
1
x_{i+1}
xi+1位,再假设
a
i
a_i
ai的周期为
T
i
T_i
Ti,
a
i
+
1
a_{i+1}
ai+1的周期为
T
i
+
1
T_{i+1}
Ti+1则当方程
x
i
+
k
i
∗
T
i
=
x
i
+
1
+
k
i
+
1
∗
T
i
+
1
x_i+k_i*T_i=x_{i+1}+k_{i+1}*T_{i+1}
xi+ki∗Ti=xi+1+ki+1∗Ti+1
有解时则可以在同一位出现,也即
(
x
i
−
x
i
+
1
)
%
g
c
d
(
T
i
,
T
i
+
1
)
=
=
0
(x_i-x_{i+1})\%gcd(T_i,T_{i+1})==0
(xi−xi+1)%gcd(Ti,Ti+1)==0时可以在相同的位置出现
因此有着连续的一段V的序列需要保证这段之间两两都满足上面这个式子.但是直接暴力比较的话时间复杂度则会过大.这时可以发现所有 T ∈ [ 1 , 40 ] T\in[1,40] T∈[1,40]因此只需要对当前的T对所有的T进行检测即可.且当两条序列有相同的T时,必须其x也相同才可以保证出现在相同的位置,因此一个周期唯一对应一个x,为此维护出所有周期的种类的x,与连续的x的数量即可.通过左右指针对所有的序列进行操作当右指针继续前进会与已经选择的区段产生冲突之后停止右指针的更新,反将左指针进行右移,并使相应的周期所对应的数的数量-1,再进行下一轮的右指针右移
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int size=1e5+5;
int n[41],cnt[41];
int T[size];
vector<int> a[size];
map<int,vector<pair<int,int>>> b;
bool check(int t,int x)
{
for(int i=1;i<=40;i++)
if(cnt[i]&&(n[i]-x)%__gcd(i,t)) return false;
n[t]=x;cnt[t]++;
return true;
}
int main()
{
int n,m;
cin>>n>>m;
int x;
for(int i=1;i<=n;i++)
{
cin>>T[i];
for(int j=1;j<=T[i];j++)
{
cin>>x;
a[i].push_back(x);
b[x].push_back(pii(i,j));
}
}
int l,r;
int ans;
for(int i=1;i<=m;i++)
{
ans=0;
memset(cnt,0,sizeof(cnt));
for(l=0,r=0;l<b[i].size();l++)
{
for(;r<b[i].size()&&b[i][r].first-b[i][l].first==r-l;r++)
if(!check(T[b[i][r].first],b[i][r].second)) break;
ans=max(ans,r-l);
cnt[T[b[i][l].first]]--;
}
cout<<ans<<endl;
}
}