zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    开发中遇到的编码的坑[开发篇]
    linux中ftp的安装过程记录[运维篇]
    在windows如何操控一些屌炸天的linux命令[利刃篇]
    php开发中应该注意的错误开关与常见处理[开发篇]
    微软职位内部推荐-Senior Development Lead
    微软职位内部推荐-Senior SDE
    微软职位内部推荐-Senior Software Development En
    微软职位内部推荐-SDEII
    微软职位内部推荐-Senior SDE
    微软职位内部推荐-Principal Software Developer
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12676167.html
Copyright © 2011-2022 走看看