CF1030G Linear Congruential Generator

Link
显然每个元素的变化轨迹都是( ho)型。
那么设第(i)个元素的轨迹的柄长为(d_i),圆周长为(l_i),那么不同的元组数量就是(maxlimits_{i=1}^n(d_i)+operatorname{lcm}limits_{i=1}^n{l_i})
我们现在考虑(a_i)的取值对于(d_i,l_i)的影响,不难发现只需要考虑(a_i,b_i,x_iin[0,p_i))的情况。

(1.a_i=0)

很显然此时(d_i=[b_i=x_i],l_i=1)。因为我们希望(d)尽可能大,所以(d_i=1)

(2.a_i=1)

很显然此时(d_i=0,l_i=p_i)

(3.a_i>1)

很显然此时(d_i=0),而(l_i=min{kinmathbb{N_+}|a_i^kx_i+b_isumlimits_{j=0}^{k-1}a_i^jequiv x_ipmod{p_i}})
变形之后得到((a_i^k-1)(x_i+frac{b_i}{a_i-1})equiv0pmod{p_i})
第二个式子与(k)是无关的,因此若(x_i+frac{b_i}{a_i-1}equiv0pmod{p_i}),那么(l_i=0),肯定不优。
因此(l_i=min{kinmathbb{N_+}|a_i^kequiv1pmod{p_i}}=p_i-1)

我们称上述为选择(1,2,3)

因为(d_ile1),因此我们可以先最大化(operatorname{lcm}limits_{i=1}^n{l_i}),再检查能否选择一个(1)
先考虑如何最大化(operatorname{lcm}limits_{i=1}^n{l_i}),我们降序枚举每个(p_i)同时维护答案(s),如果此时(p_i e s),那么最优的肯定是选择(2),否则选择(3)
具体而言维护每个质因子的最高次幂即可,为了方便之后检查能否选择(1),我们还需要记录有多少个(l_i)达到了这个最高次幂。
然后我们再次检查所有(l_i),如果它的所有质因子的最高次幂都有至少两个(l_i)达到了,那么我们将该(l_i)扔掉也不会对答案造成影响,这时候我们就可以将这个(i)改为选择(1)

#include<cctype>
#include<cstdio>
#include<algorithm>
const int N=2000007,P=1000000007;
int a[N],low[N],mx[N],num[N],vis[N];
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int read(){int x=0,c=getchar();while(isspace(c))c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return x;}
void update(int p,int x){if(x>mx[p])mx[p]=x,num[p]=1;else num[p]+=mx[p]==x;}
int check(int x)
{
    for(int p,c;x^1;)
    {
	for(p=low[x],c=0;!(x%p);x/=p,++c);
	if(c==mx[p]&&num[p]==1) return 0;
    }
    return 1;
}
int main()
{
    int n=read(),s=1,t=0;
    for(int i=1;i<=n;++i) a[i]=read();
    std::sort(a+1,a+n+1);
    for(int i=2;i<=a[n];++i) if(!low[i]) for(int j=i;j<=a[n];j+=i) if(!low[j]) low[j]=i;
    for(int i=n,v,x,p,c;i;--i)
	if(mx[v=a[i]]) for(vis[i]=1,x=v-1;x^1;s=mul(s,pow(p,std::max(0,c-mx[p]))),update(p,c)) for(p=low[x],c=0;!(x%p);x/=p,++c);
	else update(v,1),s=mul(s,v);
    for(int i=1;i<=n;++i) if((vis[i]&&check(a[i]-1))||(!vis[i]&&check(a[i]))) t=1;
//  for(int i=1;i<=n;++i) if(vis[i]&&check(a[i]-1)) t=1;
//  这里这么写判断条件也是没有问题的,分析易得其正确性。
    printf("%d",(s+t)%P);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12676167.html