20190730

互质对

题意简述

给你一个长度为 $n$ 的序列。$q$ 次操作,每次将一个数删除或加入,问操作完后的序列互质对个数。

$n,q\leq 10^5,a_i\leq 5\times 10^5$ 。

$solution:$

对于数 $x\leq 5\times 10^5$ ,它的质因子个数不超过 $7$ 个,所以直接做简单容斥即可。

时间复杂度 $O(n\sqrt{a})$ 。

写法优秀的可以为 $O(n\times 2^7)$

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=510001;
int n,q,cnt,g[MAXN],num[MAXN],M[MAXN];
inline void dfs(int ps,int res,int ans){
    if(ps==g[0]+1){
        if(res==0) return;
        if(res&1) cnt+=num[ans];
        else cnt-=num[ans];
        return;
    }
    dfs(ps+1,res+1,ans*g[ps]);
    dfs(ps+1,res,ans);
    return;
}
inline int get(int x){
    g[0]=0;
    cnt=0;
    for(register int i=2;i<=sqrt(x);++i){
        if(x%i==0) g[++g[0]]=i;
        while(x%i==0) x/=i;
    }
    if(x!=1) g[++g[0]]=x;
    dfs(1,0,1);
    
    return cnt;
}
inline void Modify(int x,int opt){
    for(register int i=1;i<sqrt(x);++i){
        if(x%i==0) num[i]+=opt,num[x/i]+=opt; 
    }
    if((int)((int)sqrt(x)*(int)sqrt(x))==x) num[(int)sqrt(x)]+=opt;
    return;
}
int a[MAXN],Ans,Num,vis[MAXN];
signed main(){
    freopen("coprime.in","r",stdin);
    freopen("coprime.out","w",stdout);
    n=read(),q=read();
    for(register int i=1;i<=n;i++) a[i]=read();
    for(register int i=1;i<=q;i++){
        int x=read();
        vis[x]^=1;
        if(vis[x]==1){
            if(a[x]==1) Ans+=Num;
            else Ans+=(Num-get(a[x]));
            Modify(a[x],1);
            Num++;
        }else{
            if(a[x]==1) Ans-=(Num-1);
            else Ans-=(Num-get(a[x]));
            Modify(a[x],-1);
            Num--;
        }
        printf("%lld\n",Ans);
    }return 0;
}
View Code

斐波那契

题意简述

$T$ 组询问,每次询问 $(F_n\mod F_k)\mod 10^9+7$ 。$F_i$ 表示斐波那切数列第 $i$ 项。

$T\leq 5\times 10^4,n,k\leq 10^{18}$ 。

$solution:$

考虑对于 $F_k$ 递推得到 $F_n$ 。

$F_{k-1}=F_1\times F_{k-1}+F_0\times F_k,F_k=F_0\times F_{k-1}+F_1\times F_k$ 。

通过 $F_i=F_{i-2}+F_{i-1}$ 可以得到 $F_n=F_{n-k}\times F_{k-1}+F_{n-k+1}\times F_k$ 。

下面公式省略 $\mod f_k$

则 $$F_n=F_{n-k}\times F_{k-1}+F_{n-k+1}\times F_k\\\equiv F_{n-k}\times F_{k-1}$$

对于 $F_{n-k}$ 依然可以迭代,设 $p=[\dfrac{n}{k}],q=n\mod k$ 。

$$F_n\equiv f_{k-1}^p\times f_q$$

通过找规律发现 $$F_{k-1}^2+F_{k-1}\times F_k-F_k^2=(-1)^k$$ 

推出 $$F_{k-1}^2\equiv (-1)^k$$

发现答案与 $p$ 的奇偶有关。

当 $p$ 为偶数时,$$F_n\equiv[(-1)^k]^{\frac{p}{2}}\times F_q$$

当 $p$ 为奇数时,我们发现无法去表达出对 $f_k$ 取模的值,考虑将 $i$ 值补为偶数。

将斐波那切数列拓展到负域中,$f_{-i}=(-1)^{i+1}\times f_i$ ,所以$$F_n\equiv F_{k-1}^{p+1}\times F_{q-k}\\\equiv  (-1)^{k-q+1}\times F_{k-1}^{p+1}\times F_{k-q}$$

然后就同 $p$ 为偶数处理即可。

每次只要用矩阵快速幂快速求出 $F$ 即可。

时间复杂度 $O(T\log k)$ 。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
#define mod 1000000007
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
struct Matrix{
    int a[3][3];
    void clear(){memset(a,0,sizeof(a));}
}F,G;
Matrix operator*(Matrix x1,Matrix x2){
    Matrix x3;x3.clear();
    for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
            for(int k=1;k<=2;k++) x3.a[i][j]+=x1.a[i][k]*x2.a[k][j],x3.a[i][j]%=mod;
    return x3;
}
Matrix ksm(Matrix a,int b){
    Matrix ans;ans.clear();
    for(int i=1;i<=2;i++) ans.a[i][i]=1;
    while(b){
        if(b&1) ans=ans*a;
        a=a*a,b>>=1;
    }return ans;
}
int Qfib(int ps){
    if(ps==0) return 0;
    if(ps==1) return 1;
    F.clear(),G.clear();
    F.a[1][1]=F.a[1][2]=F.a[2][1]=1;
    G=ksm(F,ps-1);
    return G.a[1][1];
}
int Mod(int x){return ((x%mod)+mod)%mod;}
int T,n,k;
void solve(){
    n=read(),k=read();
    if(k<=2){printf("0\n");return;}
    if(n<k){printf("%lld\n",Qfib(n));return ;}
    int p=n/k,q=n%k;
    if(q==0){printf("%d\n",0);return;}
    if(p%2==0){
        int opt=((k*(p/2))&1?-1:1);
        if(Qfib(q)==0){printf("%lld\n",0);return;}
        if(opt==1){printf("%lld\n",Qfib(q));return;}
        printf("%lld\n",Mod(Qfib(k)-Qfib(q)));
        return;
    }
    p++;
    int opt=(((k*(p/2)&1))?-1:1)*(((k-q+1)&1)?-1:1);
    if(opt==1){printf("%lld\n",Qfib(k-q));return;}
    else {printf("%lld\n",Mod(Qfib(k)-Qfib(k-q)));return;}
    return;
}
signed main(){
//    freopen("make.in","r",stdin);
    freopen("fib.in","r",stdin);
    freopen("fib.out","w",stdout);
    T=read();
    while(T--) solve();
    return 0;
}
View Code

不连续回文串

题意简述

给定一个长度为 $n$ 的 $01$ 字符串。

求出满足位置和字符均对于某条对称轴对称的不连续回文子串。

答案对 $10^9+7$ 取模。

$n\leq 10^5$ 。

$solution:$

先不考虑不连续这个限制,最后可以直接二分加哈希求出。

如果 $l,r$ 会对于 $x$ 这个位置作贡献,必须满足 $a_l=a_r,2x=l+r$ 。

直接对于 $0,1$ 分别卷积后快速幂求出对数即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define int long long
#define mod 1004535809
#define Mod 1000000007
using namespace std;
inline int read(){
    int f=1,ans=0;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return f*ans;
}
const int MAXN=400001;
int n,m,flip[MAXN],f[MAXN],g[MAXN];
int ksm(int a,int b,int MOd){
    int ans=1;
    while(b){
        if(b&1) ans*=a,ans%=MOd;
        a*=a,a%=MOd;
        b>>=1;
    }return ans;
}
inline void NTT(int *f,int opt){
    for(int i=0;i<n;i++) if(i<flip[i]) swap(f[i],f[flip[i]]);
    for(int p=2;p<=n;p<<=1){
        int len=p>>1,buf=ksm(3,(mod-1)/p,mod);
        if(opt==-1) buf=ksm(buf,mod-2,mod);
        for(int be=0;be<n;be+=p){
            int tmp=1;
            for(int l=be;l<be+len;l++){
                int t=f[l+len]*tmp;t%=mod;
                f[len+l]=(f[l]-t+mod)%mod,f[l]=(f[l]+t)%mod;
                tmp*=buf,tmp%=mod;
            }
        }
    }if(opt==-1){
        int Inv=ksm(n,mod-2,mod);
        for(int i=0;i<n;i++) f[i]*=Inv,f[i]%=mod;
    }return;
}
char str[MAXN];
int len,a[MAXN];
inline void work(int opt){
    memset(f,0,sizeof(f)),memset(g,0,sizeof(g));
    n=len,m=len;
    for(int i=1;i<=len;i++)
        if(a[i]==opt) f[i]=g[i]=1;
    m+=n;
    for(n=1;n<=m;n<<=1);
    for(int i=0;i<n;i++) flip[i]=(flip[i>>1]>>1)|(i&1?n>>1:0);
    NTT(f,1),NTT(g,1);
    for(int i=0;i<n;i++) f[i]*=g[i],f[i]%=mod;
    NTT(f,-1);
    return;
}
int ans[MAXN],Ans,pw[MAXN],Hash1[MAXN],Hash2[MAXN],Cnt;
inline int hash1(int l,int r){return Hash1[r]-Hash1[l-1]*pw[r-l+1];}
inline int hash2(int l,int r){return Hash2[l]-Hash2[r+1]*pw[r-l+1];}
inline int solve(){
    n=len;
    pw[0]=1;for(int i=1;i<=n;i++) pw[i]=pw[i-1]*3;
    for(int i=1;i<=n;i++) Hash1[i]=Hash1[i-1]*3+a[i];
    for(int i=n;i>=1;i--) Hash2[i]=Hash2[i+1]*3+a[i];
    for(int i=1;i<=n;i++){
        int l=0,r=min(i-1,n-i),Maxn=INT_MIN;
        while(l<=r){
            int mid=l+r>>1;
            if(hash1(i-mid,i)==hash2(i,i+mid)){Maxn=max(Maxn,mid);l=mid+1;}
            else r=mid-1;
        }
        Cnt+=Maxn+1;
    }
    for(int i=1;i<n;i++){
        int l=1,r=min(i,n-i),Maxn=0;
        while(l<=r){
            int mid=l+r>>1;
            if(hash1(i-mid+1,i)==hash2(i+1,i+mid)){Maxn=max(Maxn,mid);l=mid+1;}
            else r=mid-1;
        }
        Cnt+=Maxn;
    }return Cnt;
}
signed main(){
    freopen("palindrome.in","r",stdin);
    freopen("palindrome.out","w",stdout);
    scanf("%s",str+1);
    len=strlen(str+1);
    for(int i=1;i<=len;i++) a[i]=str[i]-'0';
    work(0);
    for(int i=2;i<=2*len;i++) ans[i]+=f[i],ans[i]%=Mod;
    work(1);
    for(int i=2;i<=2*len;i++) ans[i]+=f[i],ans[i]%=Mod;
    int Inv=ksm(2,Mod-2,Mod);
    for(int i=2;i<=2*len;i++){
        if(i%2==0){
            Ans+=ksm(2,((ans[i]+1)*Inv)%Mod,Mod);
            Ans--;Ans=((Ans%Mod)+Mod)%Mod;
        }else{
            Ans+=ksm(2,(ans[i]*Inv)%Mod,Mod);
            Ans--;Ans=((Ans%Mod)+Mod)%Mod;
        }
    }printf("%lld\n",(((Ans-solve())%Mod)+Mod)%Mod);return 0;
}
View Code

 

posted @ 2019-07-30 19:32  siruiyang_sry  阅读(167)  评论(0编辑  收藏  举报