Codeforces Round #539 div1

1109A. Sasha and a Bit of Relax

记 $sum[i]$ 表示前 $i$ 位的异或和,当一个 $l,r$ 可以作为答案即 $sum[l]==sum[r]$ 并且 $l,r$ 同奇偶,所以我们可以记 $v[i][0/1]$ 表示前缀异或值为 $i$ 并且所在位置为奇/偶的方案数。每位答案为在我之前前缀异或值和我相同所在位置和我同奇偶的方案数。

效率 $O(n)$

 以下代码:
#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=3e5+5,M=2e6;
LL ans;
int n,a[N],v[M][2],sum;
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
int main()
{
    n=read();v[0][0]++;
    for(int i=1;i<=n;i++){
        a[i]=read();sum^=a[i];
        ans+=v[sum][i&1];
        v[sum][i&1]++;    
    }
    printf("%I64d\n",ans);
    return 0;
}
View Code

 

1109B. Sasha and One More Name

对于一个长度为 $n$ 的回文串,只有当相同字母数 $\le n-1$ 时,才一定存在答案。否则一定无解。

考虑什么时候会有答案为 $1$ :

切一刀变成回文串,相当于把这个串结成一个环,如果从一个地方切下一刀形成的链得到与原串不相同的回文串,那么切一刀合法。

剩余的所有情况,因为我们保证回文串一定在对称的部分存在不同字母,那么一定存在一种情况在两边对称的地方切一刀,左右交换,得到新的回文串。

以下代码:
#include<bits/stdc++.h>
#define il inline
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=5005;
char s[N<<1];int n;
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
il bool pd0(){
    int mid=n>>1;
    for(int i=1;i<mid;i++){
        if(s[i]!=s[i+1])return 1;
    }
    mid++;if(n&1)mid++;
    for(int i=mid;i<n;i++){
        if(s[i]!=s[i+1])return 1;
    }
    return 0;
}
il bool pd(int l){
    int mid=n>>1;
    for(int i=1;i<=mid;i++){
        int j=l+n-i;
        if(s[l+i-1]!=s[j])return 0;
    }
    for(int i=1;i<=n;i++)if(s[i]!=s[i+l-1])return 1;
    return 0;
}
il bool pd1(){
    for(int i=2;i<=n;i++){
        if(pd(i))return 1;
    }
    return 0;
}
int main()
{
    scanf(" %s",s+1);n=strlen(s+1);
    for(int i=1;i<=n;i++)s[i+n]=s[i];
    if(n<=3||!pd0())return puts("Impossible"),0;
    if(pd1())return puts("1"),0;
    puts("2");
    return 0;
}
View Code

 

1109D. Sasha and Interesting Fact from Graph Theory

测试的时候看错题目了气哭!

考虑枚举在 $a,b$ 之间点的个数。
$$
ans=\sum_{i=0}^{min(m-1,n-2)}C_{n-2}^{i}i!C_{m-1}^{i}(i+2)n^{n-i-3}m^{n-i-2}
$$
$C_{n-2}^{i}$ 表示在除 $a,b$ 外的点中选出 $i$ 个点作为 $a,b$ 链上的点

$i!$ 表示 $a,b$ 之间的点的排列顺序

$C_{m-1}^{i}$ 表示 $a,b$ 链之间的点的长度分布(插板法)

$(i+2)n^{n-i-3}$ 表示不在链上的点的分布的方案数(根据 $Cayley$ 公式

$m^{n-i-2}$ 表示不在链上每个点连接的边不同长度的方案数

以下代码:
#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=1e6+5,p=1e9+7;
int n,m,jc[N],ny[N],ans,po[N],M[N],mx;
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
il int ksm(LL a,int y){
    LL b=1;
    while(y){
        if(y&1)b=b*a%p;
        a=a*a%p;y>>=1;
    }
    return b;
}
il int mu(int x,int y){
    return (x+y>=p)?x+y-p:x+y;
}
il int C(int n,int m){
    return 1ll*jc[n]*ny[m]%p*ny[n-m]%p;
}
int main()
{
    n=read();m=read();read();read();mx=max(n,m);
    jc[0]=1;for(int i=1;i<=mx;i++)jc[i]=1ll*i*jc[i-1]%p;
    ny[mx]=ksm(jc[mx],p-2);for(int i=mx;i;i--)ny[i-1]=1ll*i*ny[i]%p;
    po[0]=1;for(int i=1;i<=mx;i++)po[i]=1ll*n*po[i-1]%p;
    M[0]=1;for(int i=1;i<=mx;i++)M[i]=1ll*m*M[i-1]%p;
    for(int i=0;i<=min(m-1,n-2);i++){
        if(i==n-2)ans=mu(ans,1ll*C(m-1,i)*jc[i]%p);
        else ans=mu(ans,1ll*C(n-2,i)*jc[i]%p*C(m-1,i)%p*(i+2)%p*po[n-i-3]%p*M[n-i-2]%p);
    }
    printf("%d\n",ans);
    return 0;
}
View Code

1109E. Sasha and a Very Easy Test

因为模数非质数,考虑对模数质因数分解,不同质因数的个数最多只有 $10$ 个,于是我们用线段树维护区间的和,和乘法操作举荐的标记,以及每个位置每个数的权值以及对于以模数的每个质因数作为底数的指数是多少。对于除法操作可以减去除数对应质因数指数,同时对于不包含在质因数的部分与模数互质,可以用欧拉定理求逆元计算得。

以下代码:
#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=1e5+5;
int n,p,b[12],t,f,c[N];
il int ksm(LL a,int y){
    LL b=1;
    while(y){
        if(y&1)b=b*a%p;
        a=a*a%p;y>>=1;
    }
    return b;
}
struct node{
    int s,r,a[12],d;
    void clear(){
        for(int i=1;i<=t;i++)a[i]=0;
        r=d=1;
    }
    void operator+=(node x){
        for(int i=1;i<=t;i++)a[i]+=x.a[i];
        r=1ll*r*x.r%p;s=1ll*s*x.d%p;d=1ll*d*x.d%p;
    }
    void operator-=(node x){
        
        r=1ll*r*ksm(x.r,f-1)%p;s=r;
        for(int i=1;i<=t;i++)a[i]-=x.a[i],s=1ll*s*ksm(b[i],a[i])%p;
        d=s;
    }
    void operator^=(int x){
        clear();s=d=x%p;
        for(int i=1;i<=t;i++){
            while(!(x%b[i]))a[i]++,x/=b[i];
        }
        r=x%p;
    }
}val[N<<2],d;
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
il int mu(int x,int y){
    return (x+y>=p)?x+y-p:x+y;
}
il void update(int x){
    val[x].s=mu(val[x<<1].s,val[x<<1|1].s);
}
il void pushdown(int x){
    if(val[x].d==1)return;
    val[x<<1]+=val[x];
    val[x<<1|1]+=val[x];
    val[x].clear();
}
il void build(int x,int l,int r){
    if(l==r){val[x]^=c[l];return;}
    int mid=(l+r)>>1;val[x].clear();
    build(x<<1,l,mid);build(x<<1|1,mid+1,r);
    update(x);
}
il void mul(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){val[x]+=d;return;}
    int mid=(l+r)>>1;pushdown(x);
    if(ql<=mid)mul(x<<1,l,mid,ql,qr);
    if(mid<qr)mul(x<<1|1,mid+1,r,ql,qr);
    update(x);
}
il void div(int x,int l,int r,int pos){
    
    if(l==r){val[x]-=d;return;}
    
    int mid=(l+r)>>1;pushdown(x);
    if(pos<=mid)div(x<<1,l,mid,pos);
    else div(x<<1|1,mid+1,r,pos);
    update(x);
}
il int query(int x,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr)return val[x].s;
    int mid=(l+r)>>1;pushdown(x);
    int res=0;
    if(ql<=mid)res=query(x<<1,l,mid,ql,qr);
    if(mid<qr)res=mu(res,query(x<<1|1,mid+1,r,ql,qr));
    return res;
}
int main()
{
    n=read();p=read();int tmp=p;
    for(int i=2;i*i<=tmp;i++){
        if(!(tmp%i)){
            b[++t]=i;
            while(!(tmp%i))tmp/=i;
        }
    }
    if(tmp>1)b[++t]=tmp;f=p;
    for(int i=1;i<=t;i++)f-=f/b[i];
    for(int i=1;i<=n;i++)c[i]=read();
    build(1,1,n);int Q=read();
    while(Q--){
        int op=read();
        if(op==1){
            int x=read(),y=read(),z=read();
            d^=z;mul(1,1,n,x,y);
        }
        else if(op==2){
            int x=read(),z=read();
            d^=z;div(1,1,n,x);
        }
        else{
            int x=read(),y=read();
            printf("%d\n",query(1,1,n,x,y));
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Jessie-/p/10504903.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值