zoukankan      html  css  js  c++  java
  • LOJ #3096. 「SNOI2019」数论 脑洞+循环节

    碰到这种题第一反应就是找循环节.            

    我们发现我们就是要求 $a[i]+P imes k=b[i] ( mod Q)$ 中 $P$ 的 k 的个数.  

    那么对于 $a[i]$ 来说,最大步数为 $frac{T-1-a[i]}{P}$.    

    而我们发现 $a[i]+ P imes k$ 的循环节是 $P imes k=0( mod Q)$,这个循环节是 $lcm(P,Q)$,而 $k$ 的个数就是 $frac{lcm(P,Q)}{P}$ 

    枚举 $0$ ~ $Q$,然后对于 $i$ 向 $(i+P)%Q$ 连边,一定会形成若干个环长为 $frac{Q}{gcd(P,Q)}$ 的环. 

    那么,让每一个 $a[i]$ 在环上走 $frac{T-1-a[i]}{P}$ 步,算一下点权和即可. 

    upd:其实循环节大小都可以不算,直接暴力建图就行了.   

    code:  

    #include <bits/stdc++.h>         
    #define ll long long 
    #define N 1000006 
    #define setIO(s) freopen(s".in","r",stdin) 
    using namespace std;   
    ll T,ans,p[N];     
    vector<int>s[N],v[N];    
    int len,P,Q,n,m,a[N],b[N],tx[N],w[N],col[N],pos[N],num;        
    int dfs(int x,int c) 
    {
        if(col[x])   
            return 0;   
        col[x]=c;
        v[col[x]].push_back(x);  
        return tx[x]+dfs((x+P)%Q,c);    
    }    
    int find(int l,int x) 
    {
        return s[col[x]][pos[x]+l]-s[col[x]][pos[x]];   
    }
    int main() 
    { 
        // setIO("input");    
        int i,j;          
        scanf("%d%d%d%d%lld",&P,&Q,&n,&m,&T);      
        for(i=1;i<=n;++i)   
            scanf("%d",&a[i]);    
        for(i=1;i<=m;++i)  
            scanf("%d",&b[i]);    
        if(P>Q) 
        {
            swap(P,Q); 
            swap(a,b); 
            swap(n,m);      
        } 
        len=Q/__gcd(P,Q);
        for(i=1;i<=m;++i)    
            tx[b[i]]=1;    
        for(i=1;i<=n;++i)   
            p[i]=(T-1-a[i])/P;   
        for(i=0;i<Q;++i) 
        {
            if(!col[i])    
                ++num,w[num]=dfs(i,num);   
        }     
        for(i=1;i<=num;++i) 
        {
            for(j=0;j<v[i].size();++j)   
                pos[v[i][j]]=j; 
            int t=v[i].size()-1;     
            for(j=0;j<t;++j)   
                v[i].push_back(v[i][j]);    
            s[i].push_back(tx[v[i][0]]);      
            for(j=1;j<v[i].size();++j)   
                s[i].push_back(s[i][j-1]+tx[v[i][j]]);          
        }  
        for(i=1;i<=n;++i) 
        {
            ans+=(ll)(p[i]/len)*w[col[a[i]]];       
            ans+=find(p[i]%len,a[i])+tx[a[i]];     
        }
        printf("%lld
    ",ans);  
        return 0; 
    }
    

      

  • 相关阅读:
    软件质量保证(SQA)
    软件质量保证(SQA)
    在应用程序中使用 Ajax 的时机
    3月18日工作日志88250
    Eclipse 4.0计划
    3月15日工作日志88250
    Eclipse 4.0计划
    3月18日工作日志88250
    在应用程序中使用 Ajax 的时机
    3月15日工作日志88250
  • 原文地址:https://www.cnblogs.com/guangheli/p/12490566.html
Copyright © 2011-2022 走看看