退役前一个月的刷题日志

最新进度

目前题目:

1,P5664 [CSP-S2019] Emiya 家今天的饭 update on 2023.10.30

2,P5569 [SDOI2008] 石子合并 update on 2023.10.30

3,P5339 [TJOI2019] 唱、跳、rap和篮球 update on 2023.10.30

4,P9751 [CSP-J 2023] 旅游巴士【官方数据】 update on 2023.10.31

5,P2391 白雪皑皑 update on 2023.10.31

6,acwing3268 小明放学 update on 2023.11.1

7,acwing3270 数据中心 update on 2023.11.1

8,acwing3269 CIDR合并 update on 2023.11.1

9,CF526F Pudding Monsters update on 2023.11.2

10,P2501 [HAOI2006] 数字序列 update on 2023.11.2

11,P1514 [NOIP2010 提高组] 引水入城 update on 2023.11.2

12,P3154 [CQOI2009] 循环赛 update on 2023.11.3

13,CF468C Hack it! update on 2023.11.3

14,acwing3262 卖菜 update on 2023.11.3

15,acwing3263 买菜 update on 2023.11.3

16,acwing3264 元素选择器 update on 2023.11.3

17,acwing 3265 再卖菜 update on 2023.11.3

18,AT_agc006_d [AGC006D] Median Pyramid Hard update on 2023.11.4

19,P4211 [LNOI2014] LCA update on 2023.11.5

20,P7334 [JRKSJ R1] 吊打 update on 2023.11.6

P5664 [CSP-S2019] Emiya 家今天的饭

主要思路:用不考虑第三种限制的时候的方案数减去考虑第三种限制的时候的不合法方案数

(菜表示食材,s表示第i道烹饪方法可以做几种菜)

(此时枚举的是第x种菜)设f[i][j]表示当枚举到第i种做法的时候,此时枚举的菜的使用次数比其他菜的使用次数多j的方案数则可以得到方程:

f[i][j]=f[i-1][j]+f[i-1][j-1]*a[i][x]+f[i-1][j+1]*(s[i]-a[i][x])

因为当j>0时必然不符合,且反之必然符合,故用总方案数减去即可(代码中j的枚举范围从

n-i到n+i是为了防止负数)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=3000;
const int N=200;
const int mod=998244353;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,out=1;
int a[N][F],f[N][N*2],s[F];

void init(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n*2;f[i][j]=0,j++);
    }
}

int del(int x,int y){
    int num=x-y;
    while(num<0  ) num+=mod;
    while(num>mod) num-=mod;
    return num;
}

int add(int x,int y){
    int num=x+y;
    while(num<0  ) num+=mod;
    while(num>mod) num-=mod;
    return num;
}

int work(int x){
    int num=0;
    f[0][n]=1;
    init();
    for(int i=1;i<=n;i++){
        for(int j=n-i;j<=n+i;j++){
            f[i][j]=(f[i-1][j]+f[i-1][j-1]*a[i][x]%mod+f[i-1][j+1]*del(s[i],a[i][x])%mod)%mod;
        }
    }
    for(int i=1;i<=n;i++) num=(num+f[n][n+i])%mod;
    return num;
}

signed main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;a[i][j]=read(),s[i]=(s[i]+a[i][j])%mod,j++);
        out=(out*(s[i]+1))%mod;
    }
    out=del(out,1);
    for(int i=1;i<=m;i++){
        out=del(out,work(i));
    }
    cout<<out<<'\n';
    return 0;
}

P5569 [SDOI2008] 石子合并

结论题,记算法

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=6000000;
const int inf=1145141919;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,now,tail,tk,out;
int a[F];

void swap_(int &x,int &y){
    x^=y^=x^=y;
}

signed main(){
    n=read();
    for(int i=1;i<=n;a[i]=read(),i++);
    now=1,tail=n;
    while(tail-now+1>1){
        a[now-1]=inf,a[tail+1]=-inf;
        for(tk=now;tk<=tail;tk++){
            if(a[tk-1]<=a[tk+1]){
                a[tk]+=a[tk-1];
                out+=a[tk];
                for(int i=tk-1;i>=now;i--) swap_(a[i],a[i-1]);
                now++;int k=tk;
                while(now<k&&a[k-1]<a[k]) swap_(a[k],a[k-1]),k--;
                break;
            }
        }
        if(tk==tail+1){
            a[tail-1]+=a[tail];
            out+=a[tail-1];
            tail--;
        }
    }
    cout<<out<<'\n';
    return 0;
}

P5339 [TJOI2019] 唱、跳、rap和篮球

(组表示4可以讨论蔡徐坤的连续的人)

二项式反演,设f(i)为钦定有i个组的方案数,g(i)为恰好有i个组的方案数,则答案为g(0)

先默写一下公式g(n)=\sum_{i=n}^{m}(-1)^{i-n}\times C_{n}^{i}\times f(i)其中m=min(n/4,a,b,c,d),也就是最多有几组,而C中的n并不是g(n)中的n,而是n-3\times i,表示这些组的摆放方案数(利用整体法可求出,此处省略),最关键的地方在于f(i),这里先给出公式:

定义:

limit=n-4\times i

a=a-i,b=b-i,c=c-i,d=d-i

可以得到:

f(i)=\sum_{x=0}^{min(limit,a+b)}( C_{limit}^{x} \times (\sum_{k=nax(x-b,0)}^{min(a,limit)}C_{x}^{k})\times (\sum_{k=max(limit-x-d,0)}^{min(c,0)}C_{limt-x}^{k}))

下面是简化

f(i)=\sum_{x=0}^{min(limit,a+b)}( C_{limit}^{x} \times (\sum_{k=x-b}^{a}C_{x}^{k})\times (\sum_{k=limit-x-d}^{c}C_{limt-x}^{k}))

事实上我们只需要把a,b,c,d初始的时候都和n取min,并且把每个组合数的前缀和预处理出来就可以简化

理解:这个式子表示枚举喜欢唱或者跳的方案有几个,然后枚举喜欢唱的有几个,再枚举喜欢篮球的有几个,最前面的C_{limit}^{x}表示把喜欢唱或跳的人放到队列里面的方案数

这里发现一个简化思路from,有效避免了大量特判

int get(int x,int l,int r){
    if(l>r) return 0;
    if(l<=0) return S[x][r];
    return bup(S[x][r]-S[x][l-1]);
}

于是我们得到代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
const int F=2010;

int n,a,b,c,d,out;
int C[F][F],S[F][F];

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int bup(int x){
    while(x<0) x+=mod;
    return x;
}

int get(int x,int l,int r){
    if(l>r) return 0;
    if(l<=0) return S[x][r];
    return bup(S[x][r]-S[x][l-1]);
}

int f(int x){
    int ans=0,limit=n-4*x;
    int a1=a-x,b1=b-x,c1=c-x,d1=d-x;
    for(int i=0;i<=min(limit,a1+b1);i++){
        int j=limit-i;
        ans=(ans+(C[limit][i]*get(i,i-b1,a1)%mod*get(j,j-d1,c1)%mod)%mod)%mod;
    }
    return ans;
}

void init(){
    for(int i=0;i<=F-1;i++){
        C[i][0]=1;
        for(int j=1;j<=i;j++){
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
        }
    }
    for(int i=0;i<=F-1;i++){
        S[i][0]=1;
        for(int j=1;j<=F-1;j++){
            S[i][j]=(S[i][j-1]+C[i][j])%mod;
        }
    }
}

signed main(){
    freopen("try.in","r",stdin);
    n=read(),a=min(n,read()),b=min(n,read()),c=min(n,read()),d=min(n,read());
    init();
    int limit=min(n/4,min(a,min(b,min(c,d))));
    for(int i=0;i<=limit;i++){
        if(i&1){
            out-=C[n-3*i][i]*f(i)%mod;
            out=bup(out);
        }
        else    out=(out+C[n-3*i][i]*f(i)%mod)%mod;
    }
    cout<<out%mod<<'\n';
    return 0;
}

P9751 [CSP-J 2023] 旅游巴士【官方数据】

这一题比较有意思,首先我们发现到达每个点模k最多有k种状态,因此我们设dis[i][j]表示到第i个点,状态为j的时候的最早时刻,则设第A个点到第B个点有一条最晚开放时间为z的边

A.t代表到A的最早时刻

设fk=max(0,ceil(1.0*(z-A.t)/k))

则dis[B][(dis[A][A.t]+1)%k]=min(dis[B][(dis[A][A.t]+1)%k],dis[A][A.t]+1+fk*k)

 上述方程可以理解为:如果到A的时间比z大,那么直接转移,如果A的时间比z小,那么可以小z到达1节点的时间往后推即可,或许有人问,可不可能会还是这个时间,但是绕着一个环转了一圈再回来更优,这一点是否定的,因为如果你绕了换,那么到达B的状态就不一样了,我们求的是当前状态,这一点一定要搞清楚

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=6000000;
const int N=200;
const int P=10010;
const int inf=1145141919;

struct sl1{
    int x,t;
    friend bool operator< (sl1 a,sl1 b){
        return a.t>b.t;
    }
};

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int tot,n,m,k,out=inf;
int head[F],ver[F],nxt[F],edg[F];
int dis[P][N],v[F];
priority_queue<sl1> q;

void add(int x,int y,int z){
    ver[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
    edg[tot]=z;
}

void djstl(){
    q.push({1,0});
    while(q.size()){
        sl1 x=q.top();
        q.pop();
        if(v[x.x]) continue;
        v[x.x]=0;
        for(int i=head[x.x];i;i=nxt[i]){
            int y=ver[i];
            int kl=(x.t+1)%k;
            int fk=ceil(1.0*(edg[i]-x.t)/k);
            fk=max(fk,(int)0);
            if(dis[y][kl]>dis[x.x][x.t%k]+1+fk*k){
                dis[y][kl]=dis[x.x][x.t%k]+1+fk*k;
                q.push({y,dis[y][kl]});
            }
        }
    }
}

signed main(){
    freopen("try.in","r",stdin);
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),z=read();
        add(x,y,z);
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<k;j++) dis[i][j]=inf;
    }
    dis[1][0]=0;
    djstl();
    out=dis[n][0];
    if(out==inf) cout<<-1<<'\n';
    else cout<<out<<'\n';
    return 0;
}

P2391 白雪皑皑

比较好的并查集维护区间问题,可以学习一下

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=1000100;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,p,q;
int f[F],out[F];

void swap_(int &x,int &y){
    x^=y^=x^=y;
}

int get(int x){
    if(f[x]==x) return x;
    return f[x]=get(f[x]);
}

void merge(int x,int y){
    f[x]=get(y);
}

signed main(){
    n=read(),m=read(),p=read(),q=read();
    for(int i=1;i<=n;i++) f[i]=i;
    int ans=1;
    for(int i=m;i>=1;i--){
        int l=(i*p+q)%n+1,r=(i*q+p)%n+1;
        if(l>r) swap_(l,r);
        int j=r;
        while(j>=l){
            int opt=get(j);
            if(opt==j){
                out[j]=i;
                merge(j,j-1);
            }
            j=f[j];
        }
    }
    for(int i=1;i<=n;i++) cout<<out[i]<<'\n';
    return 0;
}

acwing3268 小明放学

简单模拟

#include<bits/stdc++.h>
#define int long long
using namespace std;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int r,y,g,n,tim,cl;

signed main(){
    r=read(),y=read(),g=read(),n=read();
    cl=r+y+g;
    while(n--){
        int k,t;
        k=read(),t=read();
        if(!k) tim+=t;
        else{
            if(k==1) t=r-t;
            if(k==2) t=y-t;
            if(k==3) t=g-t;
            if(k==1) t+=y;
            if(k==3) t+=r+y;
            int opt=(t+tim)%cl;
            if(opt<=r+y) tim+=(r+y-opt);
        }
    }
    cout<<tim<<'\n';
    return 0;
}

 acwing3270 数据中心

最小生成树例题

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=600010;
const int inf=1145141919;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

struct sl1{
    int l,r,z;
}len[F];

int n,m,root,out;
int f[F];

int get(int x){
    if(f[x]==x) return x;
    return f[x]=get(f[x]);
}

void merge(int x,int y){
    f[get(x)]=get(y);
}

bool cmp(sl1 a,sl1 b){
    return a.z<b.z;
}

signed main(){
    n=read(),m=read(),root=read();
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++) len[i].l=read(),len[i].r=read(),len[i].z=read();
    sort(len+1,len+1+m,cmp);
    for(int i=1;i<=m;i++){
        if(get(len[i].l)!=get(len[i].r)){
            merge(len[i].l,len[i].r);
            out=len[i].z;
        }
    }
    cout<<out<<'\n';
    return 0;
}

acwing3269 CIDR合并

简单模拟,但是题目比较难读懂

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=100010;

struct sl1{
    int x,l;
}sack[F];

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n;
int ch[F][40],f[F];
int dx[10]={1,256,65536,16777216};
int dy[10]={32,24,16,8};
string s;

bool cmp(sl1 a,sl1 b){
    if(a.x==b.x) return a.l<b.l;
    return a.x<b.x;
}

void zhuan(sl1 x1){
    int x=x1.x;
    for(int i=3;i>=0;i--){
        int l=x/dx[i];
        x%=dx[i];
        if(i) cout<<l<<".";
        else cout<<l;
    }
    cout<<"/"<<x1.l<<'\n';
}

void swap(sl1 &a,sl1 &b){
    a.x^=b.x^=a.x^=b.x;
    a.l^=b.l^=a.l^=b.l;
}

bool check(sl1 a,sl1 b){
    if(a.l>b.l) swap(a,b);
    for(int i=1;i<=a.l;i++){
        int x=(1<<(32-i));
        if((a.x&x)!=(b.x&x)){return 0;}
    }
    return 1;
}

bool check2(sl1 a,sl1 b){
    if(a.l!=b.l) return 0;
    for(int i=1;i<=a.l-1;i++){
        int x=(1<<(32-i));
        if((a.x&x)!=(b.x&x)) return 0;
    }
    return 1;
}

signed main(){
    n=read();
    for(int i=1;i<=n;i++) f[i]=i+1;
    for(int i=1;i<=n;i++){
        cin>>s;
        int j,flag=3,x=0,num=0,ff=0;
        int len=s.length();
        for(j=0;j<len;j++){
            if(s[j]>='0'&&s[j-1]<='9') x=(x<<1)+(x<<3)+s[j]-'0';
            if(s[j]=='.') x*=dx[flag],num+=x,x=0,flag--;
            if(s[j]=='/'){ff=1; break;}
        }
        num+=(x*dx[flag]);
        if(!ff) sack[i]={num,dy[flag]};
        else{
            j++,x=0;
            for(;j<len;j++){
                if(s[j]>='0'&&j<='9') x=(x<<1)+(x<<3)+s[j]-'0';
            }
            sack[i]={num,x};
        }
    }
    sort(sack+1,sack+1+n,cmp);
    int bg,fkl;
    do{
        fkl=bg=1;
        while(bg<=n){
            int nxt=f[bg];
            if(nxt>n) break;
            if(check(sack[bg],sack[nxt])){
                fkl=0;
                f[bg]=f[nxt];
            }
            else bg=f[bg];
        }
    }while(!fkl);
    do{
        fkl=bg=1;
        while(bg<=n){
            int nxt=f[bg];
            if(nxt>n) break;
            if(check2(sack[bg],sack[nxt])){
                fkl=0;
                sack[bg].l--;
                f[bg]=f[nxt];
            }
            else bg=f[bg];
        }
    }while(!fkl);
    bg=1;
    while(bg<=n){
        zhuan(sack[bg]);
        bg=f[bg];
    }
    return 0;
}

CF526F Pudding Monsters

一个相当好的题目,使我领结旋转啊不是,是心潮澎湃,可以用来复习线段树亦可锻炼思维

首先将题意转换,发现他的所有点的x,y均不同因此我们先按照x排序并把所有y统计到一个序列S中,发现如果能满足要求组成的一定是每一行每一列都有一个棋子的k*k矩阵因此可以把题目转换为求S序列中的好序列(如果区间[l,r]中的数是连续的,那么我们称它为好区间)这个转换很重要

然后我们发现倘若满足要求则该区间满足

max-min+1=r-l+1即

max-min+l-r=0

又左侧式子≥0,我们可以这样做:设置一个线段树维护以x为r的左式,并设置两个单调栈维护最大值和最小值

从左向右遍历序列,每次移动一下整个序列减1(因为r加了1)然后在单调栈弹出数的时候在线段树的对应位置加上对应差值即可(详情见代码)这样每个右节点的贡献就是1~i,把他们全部加起来就行

#include<bits/stdc++.h>
#define int long long
#define p1 p<<1
#define p2 p<<1|1
using namespace std;
const int F=2000000;
const int N=300010;

struct sl1{
    int x,y;
}sack[N],sk1[N],sk2[N];

struct sl2{
    int p,l,r,x,c,t;
}tre[F];

void build(int p,int l,int r){
    tre[p].l=l,tre[p].r=r;
    if(l==r){
        tre[p].x=l,tre[p].c=1;
        return;
    }
    int mid=(l+r)>>1;
    build(p1,l,mid);
    build(p2,mid+1,r);
    tre[p].x=tre[p1].x;
    tre[p].c=tre[p1].c;
}

void pushdo(int p){
    if(tre[p].t){
        tre[p1].x+=tre[p].t,tre[p2].x+=tre[p].t;
        tre[p1].t+=tre[p].t,tre[p2].t+=tre[p].t;
        tre[p].t=0;
    }
}

void pushup(int p){
    tre[p].x=min(tre[p1].x,tre[p2].x);
    tre[p].c=0;
    if(tre[p].x==tre[p1].x) tre[p].c+=tre[p1].c;
    if(tre[p].x==tre[p2].x) tre[p].c+=tre[p2].c;
}

void add(int p,int l,int r,int k){
    if(l>r) return;
    if(l<=tre[p].l&&tre[p].r<=r){
        tre[p].x+=k,tre[p].t+=k;
        return;
    }
    pushdo(p);
    int mid=(tre[p].l+tre[p].r)>>1;
    if(l<=mid) add(p1,l,r,k);
    if(r>mid)  add(p2,l,r,k);
    pushup(p);
}

int ask(int p,int l,int r){
    if(l>r) return 0;
    if(l<=tre[p].l&&tre[p].r<=r){
        if(!tre[p].x) return tre[p].c;
        return 0;
    }
    pushdo(p);
    int mid=(tre[p].l+tre[p].r)>>1,ans=0;
    if(l<=mid) ans+=ask(p1,l,r);
    if(r>mid)  ans+=ask(p2,l,r);
    return ans;
}

int n,tp1,tp2,out;
int a[N];

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
bool cmp(sl1 a,sl1 b){
    return a.x<b.x;
}

signed main(){
    freopen("try.in","r",stdin);
    n=read();
    for(int i=1;i<=n;i++) sack[i].x=read(),sack[i].y=read();
    sort(sack+1,sack+1+n,cmp);
    for(int i=1;i<=n;i++) a[i]=sack[i].y;
    build(1,1,n);
    for(int i=1;i<=n;i++){
        while(tp1 && sk1[tp1].y>a[i]) add(1,sk1[tp1-1].x+1,sk1[tp1].x,sk1[tp1].y-a[i]),tp1--;
        while(tp2 && sk2[tp2].y<a[i]) add(1,sk2[tp2-1].x+1,sk2[tp2].x,a[i]-sk2[tp2].y),tp2--;
        add(1,1,n,-1);
        sk1[++tp1]={i,a[i]},sk2[++tp2]={i,a[i]};
        out+=ask(1,1,i);
    }
    cout<<out<<'\n';
    return 0;
}

P2501 [HAOI2006] 数字序列

一道比较好的题目

第一问我们可以得到式子:a[i]-a[j]>=i-j,化简得到a[i]-i>=a[j]-j,设b[i]=a[i]-i,则第一问转化为求b

[i]的最长上升子序列

第二问关键在于理解当a[i],严格单调递增的时候b[i]是不下降的:

当a[i]的公差为1时,b[i]-b[j]=0,这很容易得到,倘若公差更大,则这个值会大于0,因此可以知道当a[i]严格单调递增的时候b[i]不下降

然后我们要再知道对于最终答案里面的两个数(b[i],b[j]),他们中间一定存在一个值k使得b[i]~b[k]=b[i],b[j]~b[k]=b[j],这个证明放个比较好的文章:

题解 P2501 【[HAOI2006]数字序列】 - 学委 的博客 - 洛谷博客

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=400000;
const int inf=9e18;

int n,tp,tot;
int f[F],a[F],b[F],len[F],g[F],k1[F],k2[F];
int head[F],ver[F],nxt[F];

void add(int x,int y){
    ver[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

void init(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read(),b[i]=a[i]-i;
    b[0]=-inf,b[n+1]=inf;
}

signed main(){
    freopen("try.in","r",stdin);
    init();
    for(int i=1;i<=n+1;i++){
        int l=1,r=tp,ans=-1;
        while(l<=r){
            int mid=(l+r)>>1;
            if(f[mid]>b[i]) ans=mid,r=mid-1;
            else l=mid+1;
        }
        if(ans+1){
            f[ans]=b[i];
            len[i]=ans;
        }
        else{
            f[++tp]=b[i];
            len[i]=tp;
        }
    }
    cout<<n-tp+1<<'\n';
    for(int i=1;i<=n;i++) add(len[i],i);
    for(int i=1;i<=n+1;i++) g[i]=inf;
    g[0]=0,add(0,0);
    for(int i=1;i<=n+1;i++){
        for(int k=head[len[i]-1];k;k=nxt[k]){
            int y=ver[k];
            if(y>i||b[y]>b[i]) continue;
            k1[y-1]=k2[y-1]=0;
            for(int j=y;j<=i;j++) k1[j]=k1[j-1]+abs(b[j]-b[y]);
            for(int j=y;j<=i;j++) k2[j]=k2[j-1]+abs(b[j]-b[i]);
            for(int j=y;j<=i;j++) g[i]=min(g[i],g[y]+k1[j]+k2[i]-k2[j]);
        }
    }
    cout<<g[n+1]<<'\n';
    return 0;
}

P1514 [NOIP2010 提高组] 引水入城

比较好的记忆化搜索板子题,但有些细节应该要注意

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=600;
const int inf=1145141919;

struct sl1{
    int l,r;
}ap[F][F],sack[F];

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,flag,top,head=2,tail,out;
int mapp[F][F],v[F][F];
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,1,-1};

bool cmp(sl1 a,sl1 b){
    if(a.l==b.l) return a.r>b.r;
    return a.l<b.l;
}

sl1 dfs(int x,int y){
    if(v[x][y]) return ap[x][y];
    v[x][y]=1;
    if(y==n) ap[x][y].l=ap[x][y].r=x;
    for(int i=1;i<=4;i++){
        int x1=x+dx[i],y1=y+dy[i];
        if(mapp[x1][y1]<mapp[x][y]){
            ap[x][y].l=min(ap[x][y].l,dfs(x1,y1).l);
            ap[x][y].r=max(ap[x][y].r,dfs(x1,y1).r);
        }
    }
    return ap[x][y];
}

signed main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++){
        mapp[0][i]=mapp[m+1][i]=inf;
        for(int j=1;j<=m;j++){
            mapp[j][i]=read();
            mapp[j][0]=mapp[j][n+1]=inf;
            ap[j][i].l=inf,ap[j][i].r=-inf;
        }
    }
    for(int i=1;i<=m;i++){
        if(!v[i][1]) dfs(i,1);
    }
    for(int i=1;i<=m;i++){
        if(!v[i][n]) flag++;
    }
    if(flag){
        cout<<0<<'\n'<<flag<<'\n';
        return 0;
    }
    for(int i=1;i<=m;i++){
        if(v[i][1]&&ap[i][1].l!=inf) sack[++top]=ap[i][1];
    }
    sort(sack+1,sack+1+top,cmp);
    tail=sack[1].r,out++;
    while(head<=top && tail<m){
        int now=-inf;
        while(sack[head].l<=tail+1) now=max(now,sack[head].r),head++;
        out++,tail=now;
    }
    cout<<1<<'\n'<<out<<'\n';
    return 0;
}

P3154 [CQOI2009] 循环赛

比较好的减枝题,增加一种剪枝思路:hash

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=30;
const int mod=100;
const int N=30000;

int n,top,sum,summ,hsh,sumn;
int a[F],now[F],cz[F];
map<int,int> vis;

int dfs(int x,int y){
    if(x>=n) return 1;
    if(y>n){
        if(now[x]!=a[x]) return 0;
        for(int i=x+1;i<=n;i++) cz[i]=a[i]-now[i];
        sort(cz+x+1,cz+n+1);
        hsh=0;
        for(int i=x+1;i<=n;i++) hsh=hsh*mod+cz[i];
        if(vis.find(hsh)!=vis.end()) return vis[hsh];
        else return vis[hsh]=dfs(x+1,x+2);
    }
    int ans=0;
    if(now[x]+3<=a[x] && summ){
        now[x]+=3,summ--,ans+=dfs(x,y+1),now[x]-=3,summ++;
    }
    if(now[y]+3<=a[y] && summ){
        now[y]+=3,summ--,ans+=dfs(x,y+1),now[y]-=3,summ++;
    }
    if(now[x]+1<=a[x] && now[y]+1<=a[y] && sumn){
        now[x]++,now[y]++,sumn--,ans+=dfs(x,y+1),now[x]--,now[y]--,sumn++;
    }
    return ans;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i];
    sort(a+1,a+1+n);
    summ=sum-n*(n-1),sumn=3*n*(n-1)/2-sum;//x,y
    cout<<dfs(1,2)<<'\n';
    return 0;
}

CF468C Hack it!

比较好的思维题关键点在于知道f(x+10^18)=f(x)+1(x<10^18)

#include<bits/stdc++.h>
#define i28 __int128
using namespace std;

i28 read(){
    char ch=getchar();i28 x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

i28 x,top,a,opt=1e18;
int sack[100];

void rt(i28 k){
    top=0;
    while(k){
        int opt=k%10;
        sack[++top]=opt;
        k/=10;
    }
    for(int i=top;i>=1;i--) cout<<sack[i];
    cout<<" ";
}

signed main(){
    a=read();
    rt(a-opt%a*9%a*9%a);
    rt(opt+a-opt%a*9%a*9%a-1);
    return 0;
}

acwing3262 卖菜

简单模拟

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=2010;
const int inf=1145141919;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n;
int a[F],out[F];

signed main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    a[0]=a[2],a[n+1]=a[n-1];
    for(int j=1;j<=n;j++){
        if(j==1) out[j]=(a[j+1]+a[j])/2;
        else{
            if(j==n) out[j]=(a[j-1]+a[j])/2;
            else out[j]=(a[j+1]+a[j]+a[j-1])/3;
        }
        
    }
    for(int i=1;i<=n;i++) cout<<out[i]<<" ";
    cout<<endl;
    return 0;
}

acwing3263 买菜

前缀和模版

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=2010;
const int inf=1145141919;
const int N=2e6;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

struct sl1{
    int l,r;
}sk1[F],sk2[F];

int n,la=-1,out,maxx;
int tim[N];

signed main(){
    n=read();
    for(int x,y,i=1;i<=n;i++){
        x=read(),y=read();
        x++;
        if(la==-1) la=y;
        else{
            for(int j=la+1;j<x;j++) tim[j]=tim[j-1];
            la=y;
        }
        for(int j=x;j<=y;j++){
            tim[j]=tim[j-1]+1;
        }
        maxx=max(maxx,y);
    }
    for(int x,y,j=1;j<=n;j++){
        x=read(),y=read();
        x++;
        if(y>maxx) tim[y]=tim[maxx];
        if(x>maxx) tim[x-1]=tim[maxx];
        out+=tim[y]-tim[x-1];
    }
    cout<<out<<'\n';
    return 0;
}

acwing3264 元素选择器 

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=2010;
const int P=200;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,cnt,tot,tp,op;
int last[F],out[F];
int head[F],ver[F],nxt[F],v[F];
string work[P];
map<string,int> to;
map<int,string> id,tag;
vector<int> hav[P];

void add(int x,int y){
    ver[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}

void getline_(string &s,int flag){
    char ch=getchar();
    while(ch!=10 && ch!='\0') s+=ch,ch=getchar();
}

void dfs(int x,int dep){
    if(v[x]==m) return;
    v[x]=m;
    if(id[x]==work[dep] || tag[x]==work[dep]){
        if(dep==tp){
            out[++op]=x;
            dep--;
        }
        dep++;
    }
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        dfs(y,dep);
    }
}

void zhuan(string &x){
    for(int i=0;i<x.length();i++){
        if(x[i]>='A' && x[i]<='Z') x[i]=x[i]-'A'+'a';
    }
}

signed main(){
    n=read(),m=read();
    for(int i=1;i<=n;v[i]=-1,i++){
        int chr=0;
        string s,s2,s3;
        s3+='#';
        getline(cin,s);
        while(s[chr]=='.' && chr<s.length()) chr++;
        last[chr/2]=i;
        add(last[chr/2-1],i);
        int flag=0;
        for(int j=chr;j<s.length();j++){
            if(s[j]>='A' && s[j]<='Z' && !flag) s[j]='a'+s[j]-'A';
            if(s[j]!=' ' &&  flag) s3+=s[j];
            if(s[j]=='#' && !flag) flag=1;
            if(s[j]!=' ' && !flag) s2+=s[j];
        }
        if(!to[s2]) to[s2]=++cnt;
        hav[to[s2]].push_back(i);
        id[i]=s2;
        if(s3.length()!=1){
            if(!to[s3]) to[s3]=++cnt;
            hav[to[s3]].push_back(i);
            tag[i]=s3;
        }
    }
    while(m--){
        int flag=0;
        string s;
        getline(cin,s);
        for(int i=0;i<s.length();i++){
            if(s[i]==' ') flag=1;
        }
        if(!flag){
            if(s[0]!='#') zhuan(s);
            cout<<hav[to[s]].size()<<' ';
            sort(hav[to[s]].begin(),hav[to[s]].end());
            for(int i=0;i<hav[to[s]].size();i++){
                cout<<hav[to[s]][i]<<' ';
            }
            cout<<'\n';
        }
        else{
            int head=0;
            op=tp=0;
            while(head<s.length()){
                tp++;
                string amk;
                while(s[head]!=' ' && head<s.length()) amk+=s[head],head++;
                if(amk[0]!='#') zhuan(amk);
                work[tp]=amk;
                head++;
            }
            for(int i=0;i<hav[to[work[1]]].size();i++){
                if(v[hav[to[work[1]]][i]]!=m){
                    dfs(hav[to[work[1]]][i],1);
                }
            }
            cout<<op<<" ";
            sort(out+1,out+1+op);
            for(int i=1;i<=op;i++){
                cout<<out[i]<<" ";
            }
            cout<<'\n';
        }
    }
    return 0;
}

acwing 3265 再卖菜

爆搜题

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=2010;
const int inf=1145141919;
const int N=2e6;
const int P=400;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,cnt;
int a[F],x[F],re[F],v[P][P][P];

int dfs(int k){
    for(int i=0;i<=2;i++){
        x[k]=a[k-1]-x[k-1]-x[k-2]+i;
        if(v[k][x[k]][x[k-1]]) continue;
        if(k==n && x[k]>0 && (x[k]+x[k-1])/2==re[k]){
            return 1;
        }
        if(x[k]>0){
            if(dfs(k+1)) return 1;
            else v[k][x[k]][x[k-1]]=1;
        }
    }
    return 0;
}

signed main(){
    n=read();
    for(int i=1;i<=n;i++) re[i]=a[i]=read();
    a[1]*=2,a[n]*=2;
    for(int i=2;i<n;i++) a[i]*=3;
    if(n==2){
        cout<<1<<" "<<a[1]-1<<'\n';
        return 0;
    }
    for(int i=1;i<=a[1];i++){
        x[1]=i,x[2]=a[1]-i;
        if(dfs(3)){
            for(int j=1;j<=n;j++) cout<<x[j]<<" ";
            return 0;
        }
    }
    for(int i=1;i<=a[1]+1;i++){
        x[1]=i,x[2]=a[1]-i+1;
        if(dfs(3)){
            for(int j=1;j<=n;j++) cout<<x[j]<<" ";
            return 0;
        }
    }
    return 0;
}

AT_agc006_d [AGC006D] Median Pyramid Hard

相当好的思维题,这可以用二分是我真没想到的,考虑把这个金字塔转化为0,1串,0表示小于当前二分的数,1表示大于等于当前二分的数,观察到,如果两个数连在一起,他可以一直往上走,如果没有两个数连在一起,那么发现是交替往上走,如此二分得到最顶端的数是0或1

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int F=6000000;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,l,r,len,out;
int a[F],b[F];

bool check(int x){
    int z=len/2+1,minn=F,poi=-1;
    for(int i=1;i<=len;i++) b[i]=(a[i]>=x);
    for(int i=1;i<=len;i++){
        if(b[i]==b[i+1] || b[i]==b[i-1]){
            if(minn>abs(z-i)){
                minn=abs(z-i);
                poi=i;
            }
        }
    }
    if(poi+1) return b[poi];
    return b[1];
}

signed main(){
    n=read();
    len=n*2-1;
    for(int i=1;i<=len;i++) a[i]=read();
    r=len,l=1;
    while(r>=l){
        int mid=(l+r)>>1;
        if(check(mid)){
            out=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    cout<<out<<'\n';
    return 0;
}

P4211 [LNOI2014] LCA

考虑lca的本质:lca(x,y)等价于队x到root的点+1,然后查询y到root的点值的总和,这题的方法很不错,先把一个询问拆成两个点{l,z}{r,z},然后前缀和就行

#include<bits/stdc++.h>
#define int long long
#define p1 p<<1
#define p2 p<<1|1
using namespace std;
const int F=6000000;
const int mod=201314;

struct sl1{
    int poi,l,z;
}sack[F];

struct sl2{
    int l,r,tag,val,siz;
}tre[F];

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

int n,m,tot,cnt,tp;
int head[F],ver[F],nxt[F],siz[F],mson[F],d[F],nid[F],top[F],out[F],fa[F];

void swap_(int &a,int &b){
    a^=b^=a^=b;
}

void addl(int x,int y){
    ver[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}

void build(int p,int l,int r){
    tre[p].l=l,tre[p].r=r,tre[p].siz=r-l+1;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(p1,l,mid);
    build(p2,mid+1,r);
}

void pushdown(int p){
    if(tre[p].tag){
        tre[p1].val=(tre[p1].val+tre[p].tag*tre[p1].siz%mod)%mod;
        tre[p2].val=(tre[p2].val+tre[p].tag*tre[p2].siz%mod)%mod;
        tre[p1].tag=(tre[p1].tag+tre[p].tag%mod)%mod;
        tre[p2].tag=(tre[p2].tag+tre[p].tag%mod)%mod;
        tre[p].tag=0;
    }
}

void pushup(int p){
    tre[p].val=(tre[p1].val+tre[p2].val)%mod;
}

void add(int p,int l,int r,int k){
    if(tre[p].l>=l&&tre[p].r<=r){
        tre[p].tag=(tre[p].tag+k)%mod;
        tre[p].val=(tre[p].val+tre[p].siz*k%mod)%mod;
        return;
    }
    int mid=(tre[p].l+tre[p].r)>>1;
    pushdown(p);
    if(l<=mid) add(p1,l,r,k);
    if(r>mid) add(p2,l,r,k);
    pushup(p);
}

int ask(int p,int l,int r){
    if(tre[p].l>=l&&tre[p].r<=r){
        return tre[p].val;
    }
    int mid=(tre[p].l+tre[p].r)>>1,ans=0;
    pushdown(p);
    if(l<=mid) ans=(ans+ask(p1,l,r)%mod)%mod;
    if(r>mid) ans=(ans+ask(p2,l,r)%mod)%mod;
    return ans;
}

int dfs1(int x,int f){
    int opt=-1;
    d[x]=d[f]+1;
    siz[x]=1;
    fa[x]=f;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(y==f) continue;
        siz[x]+=dfs1(y,x);
        if(opt<siz[y]){
            mson[x]=y;
            opt=siz[y];
        }
    }
    return siz[x];
}

void dfs2(int x,int f){
    nid[x]=++cnt;
    top[x]=f;
    if(mson[x]) dfs2(mson[x],f);
    else return;
    for(int i=head[x];i;i=nxt[i]){
        int y=ver[i];
        if(!nid[y]) dfs2(y,y);
    }
}

void getadd(int x,int y,int z){
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap_(x,y);
        add(1,nid[top[x]],nid[x],z);
        x=fa[top[x]];
    }
    if(d[x]>d[y]) swap_(x,y);
    add(1,nid[x],nid[y],z);
}

int getask(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(d[top[x]]<d[top[y]]) swap_(x,y);
        ans=(ans+ask(1,nid[top[x]],nid[x])%mod)%mod;
        x=fa[top[x]];
    }
    if(d[x]>d[y]) swap_(x,y);
    ans=(ans+ask(1,nid[x],nid[y]))%mod;
    return ans;
}

bool cmp(sl1 a,sl1 b){
    return a.l<b.l;
}

int del(int x,int y){
    int num=x-y;
    while(num<0) num+=mod;
    return num;
}

signed main(){
    n=read(),m=read();
    for(int x,i=2;i<=n;i++) x=read()+1,addl(x,i),addl(i,x);
    for(int i=1;i<=m;i++){
        sack[++tp].l=read(),sack[++tp].l=read()+1;
        sack[tp].z=sack[tp-1].z=read()+1;
        sack[tp].poi=sack[tp-1].poi=i;
    }
    build(1,1,n),dfs1(1,1),dfs2(1,1);
    sort(sack+1,sack+1+tp,cmp);
    int hd=1;
    while(sack[hd].l==0 && hd<=tp){
        int x=sack[hd].l,y=sack[hd].poi,z=sack[hd].z;
        if(out[y]<0) out[y]=0;
        else out[y]=0;
        hd++;
    }
    for(int i=1;i<=n;i++){
        getadd(1,i,1);
        while(sack[hd].l==i && hd<=tp){
            int x=sack[hd].l,y=sack[hd].poi,z=sack[hd].z;
            if(out[y]<0) out[y]=getask(1,z)%mod;
            else out[y]=del(getask(1,z)%mod,out[y]);
            hd++;
        }
    }
    for(int i=1;i<=m;i++) cout<<out[i]<<'\n';
    return 0;
}

P7334 [JRKSJ R1] 吊打

不错的线段树维护:维护这些值:区间平方次数最小值,区间没有平方的时候的值的最大值

如果最小平方次数为0并且执行了开方操作,直接暴力更新就行,因为一个数最多开5次就会变成1,所以最劣总开方次数只有6*n可以接受,然后利用飞马定理处理平方就行,记住平方的模数是mod-1

#include<bits/stdc++.h>
#define int long long
#define p1 p*2
#define p2 p*2+1
using namespace std;
const int F=6000000;
const int mod=998244353;
const int inf=1145141919;

int read(){
    char ch=getchar();int x=0,f=1;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}

struct sl1{
    int l,r,tag,val,maxx;
}tre[F];

int n,m,out;
int a[F];

void work(int p){
    int maxx=-inf;
    for(int i=tre[p].l;i<=tre[p].r;i++){
        a[i]=sqrt(a[i]);
        maxx=max(maxx,a[i]);
    }
    tre[p].maxx=maxx;
}

void pushup(int p){
    tre[p].maxx=max(tre[p1].maxx,tre[p2].maxx);
    tre[p].val=min(tre[p1].val,tre[p2].val);
}

void pushdown(int p){
    if(tre[p].tag){
        tre[p1].val+=tre[p].tag,tre[p1].tag+=tre[p].tag;
        tre[p2].val+=tre[p].tag,tre[p2].tag+=tre[p].tag;
        tre[p].tag=0;
    }
}

void gotto(int p){
    if(tre[p].maxx==1) return; 
    if(!tre[p].val && tre[p].l==tre[p].r){
        work(p);
        return;
    }
    if(tre[p].val){
        tre[p].val--,tre[p].tag--;
        return;
    }
    pushdown(p);
    gotto(p1),gotto(p2);
    pushup(p);
}

void build(int p,int l,int r){
    tre[p].l=l,tre[p].r=r;
    if(l==r){
        tre[p].maxx=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(p1,l,mid);
    build(p2,mid+1,r);
    pushup(p);
}

void add(int p,int l,int r,int k){
    if(tre[p].maxx==1) return;
    if(tre[p].l>=l && tre[p].r<=r){
        if(tre[p].val+k<0) gotto(p);
        else tre[p].val+=k,tre[p].tag+=k;
        return;
    }
    pushdown(p);
    int mid=(tre[p].l+tre[p].r)>>1;
    if(l<=mid) add(p1,l,r,k);
    if(r>mid) add(p2,l,r,k);
    pushup(p);
}

int pow_(int x,int y,int ml){
    int num=1;
    if(x==1) return 1;
    while(y){
        if(y&1) num=(num*x)%ml;
        x=(x*x)%ml;
        y>>=1;
    }
    return num%ml;
}

int ask(int p,int l){
    if(tre[p].l==tre[p].r) return tre[p].val;
    int mid=(tre[p].l+tre[p].r)>>1;
    pushdown(p);
    if(l<=mid) return ask(p1,l);
    else return ask(p2,l);
    pushup(p);
}

signed main(){
    //freopen("test2.in","r",stdin);
    n=read(),m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    build(1,1,n);
    while(m--){
        int z=read(),l=read(),r=read();
        if(z-1) add(1,l,r,1);
        else add(1,l,r,-1);
    }
    for(int i=1;i<=n;i++){
        int x=ask(1,i);
        if(a[i]==1) out+=1;
        else out=(out+pow_(a[i],pow_(2,x,mod-1),mod))%mod;
    }
    cout<<out<<'\n';
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值