2022年10月下旬acm训练

828div3

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int x,p[N],n,T;
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n;
        for(int i=0;i<n;i++){
    
    
            cin>>x;
            p[x]=i;
        }
        int L=n,R=-1;
        long long ans=0;
        for(int i=0;i<n;i++){
    
    
            L=min(L,p[i]),R=max(R,p[i]);
            while(i+1<n&&L<=p[i+1]&&p[i+1]<=R)i++;
            if(i==n-1){
    
    ans++;break;}
            int maxlen=(i+1)*2;
            if(R-L+1>maxlen)continue;
            int x=p[i+1];
            if(x<L){
    
    
                //x [L,R]
                for(int j=x+1;j<=L;j++){
    
    
                    if(R-j+1>maxlen)continue;
                    ans+=min(n-1-R+1,maxlen-(R-j+1)+1);
                }
            }
            if(x>R){
    
    
                //[L,R] x
                for(int j=R;j<x;j++){
    
    
                    if(j-L+1>maxlen)continue;
                    ans+=min(L-0+1,maxlen-(j-L+1)+1);
                }
            }
        }
        cout<<ans<<'\n';
    }
}

659 div1

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int x,a[N],n,T;
string ans[]={
    
    "DRAW\n","WIN\n","LOSE\n"};
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        vector<int>b(31,0);
        cin>>n;
        for(int i=1;i<=n;i++){
    
    
            cin>>x;
            for(int j=30;j>=0;j--)b[j]+=(x>>j&1);
        }
        int ok=0;
        for(int j=30;j>=0;j--){
    
    
            if(b[j]%2==0)continue;
            if(b[j]%4==1||(n-b[j])&1){
    
    ok=1;break;}
            if(b[j]%4==3){
    
    ok=2;break;}
        }
        cout<<ans[ok];
    }
}

global round22 C

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int x,a[N],n,T;
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n;
        int b=0,a=0;
        for(int i=1;i<=n;i++){
    
    
            cin>>x;
            if(x&1)b++;
            else a++;
        }
        int ok=1;
        if(b%4==1&&(a%2==0))ok=0;
        if(b%4==2)ok=0;
        if(ok)cout<<"Alice"<<'\n';
        else cout<<"Bob"<<'\n';
    }
}

828div3 E2

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,M=1e9;
int T,a,b,c,d;
map<int,int>mp;
typedef pair<int,int>PII;
typedef vector<PII> vi;
void solve(int a){
    
    
    for(int i=2;i*i<=a;i++){
    
    
        if(a%i==0){
    
    
            while(a%i==0)a/=i,mp[i]++;
        }
    }
    if(a>1)mp[a]++;
}
vi ans;
int qpow(int a,int b){
    
    
    int ans=1;
    while(b){
    
    
        if(b&1)ans=ans*a;
        b/=2;
        a=a*a;
    }
    return ans;
}
void dfs(int u,vi v,int i=1,int j=1){
    
    
    if(u==v.size()){
    
    
        int x=c/i*i;
        int y=d/j*j;
        if(x>a&&y>b)ans.push_back({
    
    x,y});
        return;
    }
    if(i>c||j>d)return;
    if(ans.size())return;
    int x=v[u].first;
    int c=v[u].second;
    for(int f=0;f<=c;f++){
    
    
        dfs(u+1,v,i*qpow(x,f),j*qpow(x,c-f));
    }
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>a>>b>>c>>d;
        mp.clear();solve(a),solve(b);
        vi v;
        for(auto &[x,c]:mp)v.push_back({
    
    x,c});
        ans.clear();
        dfs(0,v);
        if(ans.size())cout<<ans[0].first<<" "<<ans[0].second<<'\n';
        else cout<<"-1 -1\n";
    }
}

edu137 E

#include<bits/stdc++.h>
using namespace std;
#define int long long
int p1,t1,p2,t2,h,s;
int f[5050],g[5050],dp[5050];
signed main(){
    
    
    cin>>p1>>t1>>p2>>t2>>h>>s;
    for(int i=0;i<=5000;i++)f[i]=1e18,g[i]=1e18,dp[i]=1e18;
    f[0]=0;
    for(int i=0;i<=h;i++){
    
    
        for(int j=0;j<=h;j++){
    
    
            int tf=max(t1* i   ,t2* j   );
            int tg=max(t1*(i+1),t2*(j+1));
            int x=i*(p1-s)+j*(p2-s);
            int y=min(x,h);
            f[y]=min(f[y],tf);
            g[y]=min(g[y],tg);
        }
    }
    f[0]=0;
    for(int i=0;i<=h;i++){
    
    
        for(int j=0;j<=h;j++){
    
    
            int x=i+j+(p1+p2-s);
            x=min(x,h);
            f[x]=min(f[x],f[i]+g[j]);
        }
    }
    cout<<f[h];
}

DDP

动态动态规划
也就是在动态规划处理静态问题的基础上加入修改操作
修改矩阵乘法变成 max矩阵加
比较典型的有带修子段和,带修树上最大权独立集(没有上司的舞会带修版)
传送门

luogu

#include<bits/stdc++.h>
#define end End
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int N=4e5+10;
const int inf=0x7f7f7f7f;
struct Matrix{
    
    
    int a[2][2];
    Matrix(){
    
    memset(a,-0x3f,sizeof a);}
    Matrix operator*(Matrix b){
    
    
        Matrix c;
        for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
        for(int k=0;k<2;k++)
        {
    
    c.a[i][j]=max(c.a[i][j],a[i][k]+b.a[k][j]);}
        return c;
    }
    void pr(){
    
    
        cout<<"a00="<<a[0][0]<<" a01="<<a[0][1]<<'\n';
        cout<<"a10="<<a[1][0]<<" a11="<<a[1][1]<<'\n';
        cout<<'\n';
    }
}V[N];
int n,m,h[N],e[N],ne[N],idx,sz[N],fa[N],dep[N];
int a[N],top[N],id[N],dfn[N],end[N];
int son[N];
struct SegTree{
    
    
    int L[N],R[N];
    Matrix M[N];
    void pushup(int u){
    
    M[u]=M[ls]*M[rs];}
    void build(int u,int l,int r){
    
    
        L[u]=l,R[u]=r;
        if(l==r){
    
    
            M[u]=V[dfn[l]];
            // cout<<"u="<<u<<" L="<<l<<" R="<<r<<'\n';
            // M[u].pr();
            return;
        }
        int mid=l+r>>1;
        build(ls,l,mid),build(rs,mid+1,r);
        pushup(u);
    }
    void modify(int u,int x){
    
    
        if(L[u]==R[u]){
    
    
            M[u]=V[dfn[x]];
            return;
        }
        int mid=L[u]+R[u]>>1;
        if(x<=mid)modify(ls,x);
        else modify(rs,x);
        pushup(u);
    }
    // 查询一个点的 DP 值,相当于查询这条重链上链尾矩阵和链中转移矩阵的 '*' 积
    Matrix query(int u,int l=1,int r=n){
    
    
        if(L[u]==l&&R[u]==r)return M[u];
        int mid=L[u]+R[u]>>1;
        if(r<=mid)return query(ls,l,r);
        else if(l>mid)return query(rs,l,r);
        else return query(ls,l,mid)*query(rs,mid+1,r);
    }
    
}T;
void add(int a,int b){
    
    
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs1(int u,int F=0){
    
    
    sz[u]=1,fa[u]=F,dep[u]=dep[F]+1;
    for(int i=h[u];~i;i=ne[i]){
    
    
        int j=e[i];
        if(j==F)continue;
        dfs1(j,u);
        sz[u]+=sz[j];
        if(sz[son[u]]<sz[j])son[u]=j;
    }
}
int cntv;
int f[N][2],g[N][2];
void dfs2(int u,int t=1){
    
    
    cntv++;
    id[u]=cntv,dfn[cntv]=u;
    top[u]=t;
    end[t]=max(end[t],cntv);
    // 第二次树剖时直接更新 F, G 数组(这里直接将 G 放入矩阵更新)
    f[u][0]=0,f[u][1]=a[u];
    V[u].a[0][0]=0,   V[u].a[0][1]=0;
    V[u].a[1][0]=a[u];//,V[u].a[1][1]=inf;
    if(son[u]){
    
    
        dfs2(son[u],t);
        f[u][0]+=max(f[son[u]][0],f[son[u]][1]);
        f[u][1]+=f[son[u]][0];
    }
    for(int i=h[u];~i;i=ne[i]){
    
    
        int j=e[i];
        if(j==fa[u]||j==son[u])continue;
        dfs2(j,j);
    
        f[u][0]+=max(f[j][0],f[j][1]);
        f[u][1]+=f[j][0];
        V[u].a[0][0]+=max(f[j][0],f[j][1]);
        V[u].a[0][1]=V[u].a[0][0];
        V[u].a[1][0]+=f[j][0];
    }
}
void update_path(int u,int w){
    
    
    V[u].a[1][0]+=w-a[u];
    a[u]=w;
    Matrix pre,nxt;
    while(u!=0){
    
    
        // 计算贡献时,应当用一个 bef 矩阵还原出少掉这个轻儿子的情况,再将 aft 加入更新
        
        pre=T.query(1,id[top[u]],end[top[u]]);
        T.modify(1,id[u]);
        nxt=T.query(1,id[top[u]],end[top[u]]);
        u=fa[top[u]];
        
        V[u].a[0][0]+=max(nxt.a[0][0],nxt.a[1][0])-max(pre.a[0][0],pre.a[1][0]);
        V[u].a[0][1]=V[u].a[0][0];
        V[u].a[1][0]+=nxt.a[0][0]-pre.a[0][0];
    }
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    memset(h, -1, sizeof h);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++){
    
    
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    dfs1(1);dfs2(1);
    T.build(1,1,n);
    // cout<<"f="<<max(f[1][0],f[1][1])<<'\n';
    // Matrix ans=T.query(1,id[1],end[1]);
    // cout<<"V="<<max(ans.a[0][0],ans.a[1][0])<<'\n';
    while(m--){
    
    
        int u,w;
        cin>>u>>w;
        update_path(u,w);
        Matrix ans=T.query(1,id[1],end[1]);
        cout<<max(ans.a[0][0],ans.a[1][0])<<'\n';
    }
}

arc151 C

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
#define int long long
const int N=2e5+10;
int n,m,ans;
typedef pair<int,int>PII;
PII a[N];
string op[]={
    
    "Aoki","Takahashi"};
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=m;i++)cin>>a[i].x>>a[i].y;
    sort(a+1,a+1+m);
    if(!m){
    
    
        if(n&1)ans=1;
        cout<<op[ans];
        return 0;
    }
    ans^=a[1].x-1;
    ans^=n-a[m].x;
    for(int i=2;i<=m;i++){
    
    
        if(a[i].y==a[i-1].y)ans^=1;
    }
    if(ans)ans=1;
    cout<<op[ans];
}

edu137F

考虑每一个数字的贡献,也就是考虑让数字保留在最终集合里面
发现对于数字x的贡献,只有最后一次出现x的集合Si,前面无论操作是啥都不用管,后面保留下来就行了
这样的就是3的i-2次方乘2的n-i+1次方,但是起点需要特判
解法一就是线段树维护每个数字最后一次出现的下标(最大下标)
解法二就是ddp,线段树维护每一个数字,然后你需要对整棵树做dp,维护矩阵链乘注意细节

#include<bits/stdc++.h>
#define ls u<<1
#define rs u<<1|1
using namespace std;
#define int long long
const int mod=998244353;
const int N=3e5+10;
int n,a[N*4],l,r,ans;
int qpow(int a,int b){
    
    
    int ans=1;
    while(b){
    
    
        if(b&1)ans=ans*a%mod;
        b/=2;
        a=a*a%mod;
    }
    return ans;
}
void pushdown(int u){
    
    
    a[ls]=max(a[ls],a[u]);
    a[rs]=max(a[rs],a[u]);
    
}
void update(int u,int ql,int qr,int i,int l=0,int r=3e5){
    
    
    if(ql<=l&&r<=qr)return a[u]=i,void();
    if(ql>r||qr<l)return;
    int mid=l+r>>1;
    pushdown(u);
    update(ls,ql,qr,i,l,mid);
    update(rs,ql,qr,i,mid+1,r);
}
int query(int u,int x,int l=0,int r=3e5){
    
    
    if(l==r)return a[u];
    int mid=l+r>>1;
    pushdown(u);
    if(x<=mid)return query(ls,x,l,mid);
    return query(rs,x,mid+1,r);
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);
    memset(a,-1,sizeof a);
    cin>>n;
    for(int i=1;i<=n;i++){
    
    
        cin>>l>>r;
        update(1,l,r,i);
    }
    for(int i=0;i<=3e5;i++){
    
    
        int j=query(1,i);
        if(j==-1)continue;
        if(j==1)ans+=qpow(2,n-1);
        else ans+=qpow(3,j-2)*qpow(2,n-j+1)%mod;
        ans%=mod;
    }
    cout<<ans;
}

#include<bits/stdc++.h>
#define int long long
#define ls u<<1
#define rs u<<1|1
using namespace std;
const int mod=998244353;
const int N=3e5+1;
int m,l,r,x,ans;
struct Matrix{
    
    
    // int a[2][2]={1,0,0,1};//不可以这样初始化
    int a[2][2];
    Matrix(){
    
    
        memset(a,0,sizeof a);
        a[0][0]=1; 
        a[1][1]=1;
    }
    Matrix(int i1,int i2,int i3,int i4){
    
    
        a[0][0]=i1;
        a[0][1]=i2;
        a[1][0]=i3;
        a[1][1]=i4;
    }
    Matrix operator*(Matrix b){
    
    
        Matrix c;
        memset(c.a,0,sizeof c.a);
        //记住教训,一定要清空第三方数组 
        for(int i=0;i<2;i++){
    
    
            for(int j=0;j<2;j++){
    
    
                for(int k=0;k<2;k++){
    
    
                    c.a[i][j]+=a[i][k]*b.a[k][j];
                    c.a[i][j]%=mod;
                }
            }
        }
        return c;
    }
    bool operator==(Matrix B){
    
    
        int ok=1;
        for(int i=0;i<2;i++)for(int j=0;j<2;j++)
        if(a[i][j]!=B.a[i][j])return 0;
        return 1;
    }
    void pr(){
    
    
        for(int i=0;i<2;i++){
    
    
            for(int j=0;j<2;j++)cout<<" a["<<i<<"]["<<j<<"]="<<a[i][j];
            cout<<'\n';
        }
    }
}E;
struct Segmentree{
    
    
    Matrix a[N*4];
    void pushdown(int u){
    
    
        if(a[u]==E)return;
        a[ls]=a[ls]*a[u];
        a[rs]=a[rs]*a[u];
        a[u]=E;
        //变回单位矩阵
    }
    void update(int u,int ql,int qr,Matrix x,int l=0,int r=3e5){
    
    
        if(ql<=l&&r<=qr){
    
    
            return a[u]=a[u]*x,void();
        }
        if(ql>r||qr<l)return;
        pushdown(u);
        int mid=l+r>>1;
        update(ls,ql,qr,x,l,mid);
        update(rs,ql,qr,x,mid+1,r);
    }
    Matrix query(int u,int x,int l=0,int r=3e5){
    
    
        if(l==r)return a[u];
        pushdown(u);
        int mid=l+r>>1;
        if(x<=mid)return query(ls,x,l,mid);
        return query(rs,x,mid+1,r);
    }
}T;
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    // E.pr();
    // E=E*Matrix({1,0,0,0});
    // E.pr();
    cin>>m;
    cin>>l>>r;
    T.update(1,0,l-1,{
    
    1,0,0,0});
    T.update(1,l,r,{
    
    0,1,0,0});
    T.update(1,r+1,3e5,{
    
    1,0,0,0});
    for(int i=1;i<m;i++){
    
    
        cin>>l>>r;
        T.update(1,0,l-1,{
    
    3,0,1,2});
        T.update(1,l,r,{
    
    1,2,1,2});
        T.update(1,r+1,3e5,{
    
    3,0,1,2});
    }
    for(int x=0;x<=3e5;x++){
    
    
        ans+=T.query(1,x).a[0][1];
        ans%=mod;
    }
    cout<<ans;
}


2022寒假基础训练营补题

6

B

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int a[N],n,T,ans,p[N];
const int mod=998244353;
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    p[0]=1;
    for(int i=1;i<N;i++)p[i]=p[i-1]*2%mod;
    while(T--){
    
    
        ans=1;
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++){
    
    
            int j=i;
            while(j<n&&a[j]==a[j+1])j++;
            int len=j-i+1;
            int ni=a[i-1]<a[i]&&a[i]<a[j+1];
            int sh=a[i-1]>a[i]&&a[i]>a[j+1];
            if(i>1&&j<n&&(ni||sh))ans=ans*p[len]%mod;
            else ans=ans*(p[len]-1)%mod;
            i=j;
        }
        cout<<ans<<'\n';
    }
}

C

离线,找特性,猜结论
把合法答案的放进栈里面,二分找不得不选的美丽数组
我是l-1,往右边找第一个sumj满足sumj - sumi-1 < 0

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=5e6+10;
int T,n,a[N],L[N],R[N],x,ans[N],stk[N],top,m;
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n>>m;
        for(int i=1;i<=n;i++)cin>>a[i],a[i]+=a[i-1];
        for(int i=1;i<=m;i++)cin>>L[i]>>R[i];
        top=0;
        stk[++top]=n;
        int j=n-1;
        for(int i=m;i>=1;i--){
    
    
            while(j>=L[i]-1){
    
    
                while(top&&a[stk[top]]>=a[j])top--;
                stk[++top]=j;
                j--;
            }
            int l=1,r=top;
            while(l<r){
    
    
                int mid=l+r>>1;
                if(stk[mid]<R[i])r=mid;
                else l=mid+1;
            }
            ans[i]=top-l+1;
        }
        for(int i=1;i<=m;i++)cout<<ans[i]<<'\n';
    }
}

G

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N=1010;
char a[N][N];
int n,m,T,f[N][N];
int xx[]={
    
    -1,1,0,0};
int yy[]={
    
    0,0,-1,1};
char dir[]={
    
    'U','D','L','R'};
typedef pair<int,int>PII;
int pre[N][N];
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n>>m;
        for(int i=1;i<=n;i++){
    
    
            for(int j=1;j<=m;j++)cin>>a[i][j],f[i][j]=1e9;
        }
        deque<PII>q;
        q.push_back({
    
    1,1});
        f[1][1]=0;
        while(q.size()){
    
    
            int x=q.front().x;
            int y=q.front().y;
            q.pop_front();
            for(int i=0;i<4;i++){
    
    
                int dx=x+xx[i];
                int dy=y+yy[i];
                if(dx<1||dx>n||dy<1||dy>m)continue;
                if(f[x][y]+(a[x][y]!=dir[i])<f[dx][dy]){
    
    
                    f[dx][dy]=f[x][y]+(a[x][y]!=dir[i]);
//                     pre[dx][dy]={x,y};
                    pre[dx][dy]=i;
                    if(a[x][y]==dir[i])q.push_front({
    
    dx,dy});
                    else q.push_back({
    
    dx,dy});
                }
            }
        }
        cout<<f[n][m]<<"\n";
        while(1){
    
    
            if(n==1&&m==1)break;
            int i=pre[n][m];
            int x=n-xx[i];
            int y=m-yy[i];
            if(a[x][y]!=dir[i])cout<<x<<" "<<y<<" "<<dir[i]<<"\n";
            n=x,m=y;
        }
    }
}

H

非常非常好的一道题

#include<bits/stdc++.h>
using namespace std;
int T,n,ans,x;
string op[]={
    
    "No\n","Yes\n"};
unordered_map<int,int>mp;
//必败态只能走到必胜态,走不到必败态
int dfs(int u){
    
    
    if(mp.count(u))return mp[u];
    int bai=0;
    if(u&1)bai|=!dfs(u-1);
    for(int i=1;i<10;i++){
    
    
        if(u>>i&1){
    
    
            for(int j=0;j<i;j++){
    
    
                int x=u^(1<<i)^(1<<j);
                bai|=!dfs(x);
            }
        }
    }
    if(!bai)return mp[u]=0;
    else return mp[u]=1;
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    mp[0]=0;
    for(int i=(1<<10)-1;i;i--){
    
    
        if(!mp.count(i))dfs(i);
    }
    cin>>T;
    while(T--){
    
    
        cin>>n;
        x=0;
        for(int i=0;i<n;i++){
    
    
            char c;
            cin>>c;
            if(c=='w')x+=1<<i;
        }
        cout<<op[mp[x]];
    }
}

J


51nod1514 美妙的序列 分治NTT


牛客寒假基础训练营第一场

D

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+10;
int T,n;
int a[]={
    
    2,3,5,7,11,13,17,19,23,29,31};
int check(int x){
    
    
    for(int i=2;i*i<=x;i++){
    
    
        if(x%i==0)return 0;
    }
    return 1;
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n;
        if(n==1){
    
    
            cout<<-1<<'\n';
            continue;
        }
        int mi=1;
        for(int i=0;i<10;i++){
    
    
            if(mi*a[i]>n)break;
            mi*=a[i];
        }
        while(!check(n))n--;
        cout<<mi<<" "<<n<<'\n';
    }
}

F

解法一,找性质,考虑每个数字对答案的贡献求前缀
按照题意,偶数时取min(中间左,中间右),
要想变成中位数,那么比m大的数字个数>=比m小的个数+1
牛客题解传送门

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int T,n,m,a[N],x;
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n>>m;
        int ans=0;
        for(int i=1;i<=n;i++){
    
    
            cin>>x;
            if(x>=m)ans++;
            else ans--;
        }
        if(ans<=0)ans=-1;
        cout<<ans<<'\n';
    }
}


解法2,线段树优化dp(垃圾)

这道题可以拓展,也就是说它的m给你了,那么所有的ai就都可以映射到1,-1
我可以改为给q询问L,R之间可划分为中位数的最大段数


B

解法1,分块

#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=2e5+10,D=500;
int n,q,a[N],f[N];
string s;
// unordered_map<int,int>mp[3];
int mp[3][N];
int vis[N];
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>q>>s;
    s=' '+s;
    int l=1;
    int v[]={
    
    0,1,2};
    for(int i=1;i<=n;i++){
    
    
        if(s[i]=='W')for(int j=0;j<3;j++)v[j]++;
        if(s[i]=='L')for(int j=0;j<3;j++)if(v[j]%3)v[j]--;
        if(i-l+1==D){
    
    
            vis[l]=1;
            for(int j=0;j<3;j++)mp[j][l]=v[j]-j;
            l+=D;    
            for(int j=0;j<3;j++)v[j]=j;
        }
    }
    while(q--){
    
    
        int l,r,t;
        cin>>l>>r>>t;
        while(l<=r){
    
    
            if(vis[l]&&l+D-1<=r){
    
    
                t+=mp[t%3][l],l+=D;
            }
            else {
    
    
                if(s[l]=='W')t++;
                if(s[l]=='L')if(t%3)t--;
                l++;
            }
        }
        cout<<t<<'\n';
    }
}

解法2,倍增解决,
如何处理好区间合并

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
int f[N][21][3],n,q,l,r,v;
string s;
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>q>>s;
    s=' '+s;
    for(int i=1;i<=n;i++){
    
    
        for(int j=0;j<3;j++){
    
    
            if(j==0&&s[i]=='L')f[i][0][j]=0;
            else if(s[i]=='L')f[i][0][j]=-1;
            else if(s[i]=='W')f[i][0][j]=1;
        }
    }
    for(int k=1;k<=18;k++){
    
    
        for(int i=1;i<=n;i++){
    
    
            for(int j=0;j<3;j++){
    
    
                int x=(j+f[i][k-1][j])%3;
                f[i][k][j]=f[i][k-1][j]+f[i+(1<<k-1)][k-1][x];
            }
        }
    }
    while(q--){
    
    
        cin>>l>>r>>v;
        for(int k=18;k>=0;k--){
    
    
            if((1<<k)<=r-l+1){
    
    
                v+=f[l][k][v%3];
                l+=1<<k;
            }
        }
        cout<<v<<'\n';
    }
}

K

dp,枚举初始状态,初始状态确定了才可以进行枚举
这道题难点就是初始状态不确定无法进行枚举

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,f[N][3][3],ans;//f[i][j][k]表示第i位是j前面是k是否合法RGB==012
int dp[N];
string s;
int check(int op,int a,int b,int c){
    
    
    int cnt[3]={
    
    0,0,0};
    cnt[a]++,cnt[b]++,cnt[c]++;
    if(op==0)return cnt[0]>cnt[1];
    if(op==1)return cnt[0]<cnt[1];
    if(op==2)return cnt[0]==cnt[1];
    return 1;
}
int cal(int i1,int i2){
    
    
    memset(f,-1,sizeof f);
    f[2][i2][i1]=0;
    if(i2==1)f[2][i2][i1]++;
    if(i1==1)f[2][i2][i1]++;
    for(int i=3;i<=n;i++){
    
    
        for(int j=0;j<3;j++){
    
    
            for(int k=0;k<3;k++){
    
    
                if(f[i-1][j][k]==-1)continue;
                if(s[i]=='R')for(int x=0;x<3;x++)if(check(0,x,j,k))f[i][x][j]=max(f[i][x][j],f[i-1][j][k]+(x==1));
                if(s[i]=='G')for(int x=0;x<3;x++)if(check(1,x,j,k))f[i][x][j]=max(f[i][x][j],f[i-1][j][k]+(x==1));
                if(s[i]=='B')for(int x=0;x<3;x++)if(check(2,x,j,k))f[i][x][j]=max(f[i][x][j],f[i-1][j][k]+(x==1));
            }
        }
    }
    int ma=-1;
    for(int i=0;i<3;i++)for(int j=0;j<3;j++)ma=max(ma,f[n][i][j]);
    return ma;
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>s;
    s=' '+s;
    ans=-1;
    for(int i=0;i<3;i++)for(int j=0;j<3;j++)ans=max(ans,cal(i,j));
    cout<<ans;
    
    
    
    
}

H

值域树状数组,考虑每一个数字的贡献

/*
ai与多少个aj加起来是大于1000的,与多少个aj加起来是小于1000的
总和就是 x (ai+aj-1000) + y (1000-ai-aj)
*/
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,a[N],ans,s,t;
struct Tree{
    
    
    int tr[1010];
    void add(int x,int c){
    
    
        x++;
        for(int i=x;i<=1001;i+=i&-i)tr[i]+=c;
    }
    int sum(int x){
    
    
        x++;
        int ans=0;
        for(int i=x;i;i-=i&-i)ans+=tr[i];
        return ans;
    }
}cnt,val;
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];
        s+=a[i];
        cnt.add(a[i],1);
        val.add(a[i],a[i]);
        
        t+=abs(a[i]+a[i]-1000);
    }
    for(int i=1;i<=n;i++){
    
    
        int y=cnt.sum(1000-a[i]);
        int x=n-y;
        int v=val.sum(1000-a[i]);
        int Y=y*1000-y*a[i]-v;
        int X=x*a[i]+(s-v)-x*1000;
        ans+=X+Y;
    }
    cout<<(ans+t)/2;
}

I

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
int T,n,m;
int qpow(int a,int b){
    
    
    int ans=1;
    while(b){
    
    
        if(b&1)ans=ans*a%mod;
        b/=2;
        a=a*a%mod;
    }
    return ans;
}
int inv(int a){
    
    
    return qpow(a,mod-2);
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n>>m;
        int p=2*inv(qpow(2,n));
        p=1-p;
        cout<<(m*p%mod+mod)%mod<<'\n';
        
    }
}

第二场

G

你记录的信息只能是根到我这个节点的,而不可能是我到根节点的,因为这是多对一和一对一的关系

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,m,a[N];
signed fa[N][21];
int dep[N],up[N],d[N];
vector<int>g[N];
//sum[u]表示从u出发跳到根节点的代价
//那么从根节点跳到u的代价就是-sum
void dfs(int u,int F=0){
    
    
    if(a[u]>a[F])up[u]=up[F]+0;
    else up[u]=up[F]+a[F]-a[u];
    
    if(a[F]>a[u])d[u]=d[F]+0;
    else d[u]=d[F]+a[u]-a[F];
    dep[u]=dep[F]+1;
    fa[u][0]=F;
    for(int k=1;k<=20;k++)fa[u][k]=fa[fa[u][k-1]][k-1];
    for(auto j:g[u]){
    
    
        if(j==F)continue;
        dfs(j,u);
        // if(a[u]>a[j])d[u]=d[j]+0;
        // else d[u]=d[j]+a[j]-a[u];
        
    }
}
int lca(int a,int b){
    
    
    if(dep[a]<dep[b])swap(a,b);
    for(int k=20;k>=0;k--)if(dep[fa[a][k]]>=dep[b])a=fa[a][k];
    if(a==b)return a;
    for(int k=20;k>=0;k--){
    
    
        if(fa[a][k]!=fa[b][k]){
    
    
            a=fa[a][k],b=fa[b][k];
        }
    }
    return fa[a][0];
}
signed main(){
    
    
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<n;i++){
    
    
        int a,b;
        cin>>a>>b;
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs(1);
    // for(int i=1;i<=n;i++)cout<<"up["<<i<<"]="<<up[i]<<'\n';
    // for(int i=1;i<=n;i++)cout<<"down["<<i<<"]="<<d[i]<<'\n';
    while(m--){
    
    
        int u,v;
        cin>>u>>v;
        int f=lca(u,v);
        // cout<<"u="<<u<<" v="<<v<<" f="<<f<<'\n';
        cout<<a[u]+up[u]-up[f]+d[v]-d[f]<<'\n';
    }
}

猜你喜欢

转载自blog.csdn.net/supreme567/article/details/127371070