1. 程式人生 > 其它 >「考試總結2021-08-12」 模擬3

「考試總結2021-08-12」 模擬3

A. 翻轉硬幣 B.迴文子串 C.最大價值

翻轉硬幣

發現區間操作可以轉化為差分後的兩點異或

\(1\) 的位置的數量不超過 \(2k=20\),這樣子考慮狀壓 \(\rm{DP}\)

預處理翻轉某個點和距離其為 \(i\) 的點的最小代價,這部分可以 \(\rm{BFS}\) 實現,那麼轉移是簡單的

迴文子串

\(k\) 很小,維護 \(k\) 個線段樹,下標為 \(i\) 就表示起始點為 \(i\) 時當前長度的字串是不是迴文串

查詢時是線段樹的簡單區間操作,修改時大塊直接賦值為 \(1\)

邊角非常少,一共不到 \(4k=200\),把這些串大力求出來判一下修改就行了

這裡不能寫 \(Hash\),因為線段樹維護 \(Hash\) 帶的 \(\log\)

均攤完了會被打爆

$\texttt{Talk is cheap,Show the Code}$
#include<bits/stdc++.h>
using namespace std;
#define reg register
#define rep(i,a,b) for(reg int i=a;i<=b;++i) 
#define Down(i,a,b) for(reg int i=a;i>=b;--i) 
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
template<typename T>inline void ckmax(T &x,T y){x=x<y?y:x; return ;}
template<typename T>inline void ckmin(T &x,T y){x=x>y?y:x; return ;}
namespace yspm{
    inline int read(){
        int res=0,f=1; char k;
        while(!isdigit(k=getchar())) if(k=='-') f=-1;
        while(isdigit(k)) res=res*10+k-'0',k=getchar();
        return res*f;
    }
    char OPUT[100];
    inline void print(ll x){
        int cnt=0; if(x==0) return putchar('0'),putchar(' '),void(); 
        if(x<0) putchar('-'),x=-x; while(x) OPUT[++cnt]=x%10,x/=10;
        while(cnt--) putchar(OPUT[cnt+1]+'0'); putchar(' '); return ;
    }
    const int N=5e4+10;
    char s[N];
    int n,k,Q;
    struct Hash_Tree{
        int tag[N<<2],len[N<<2];
        ull sr[N<<2],sl[N<<2];
        inline void push_down(int p,int l,int r){
            if(!tag[p]) return ; int mid=(l+r)>>1;
            if(r-mid==1) s[r]=tag[p]+'a'-1; else tag[p<<1|1]=tag[p];
            if(l==mid) s[l]=tag[p]+'a'-1; else tag[p<<1]=tag[p]; 
            return tag[p]=0,void();
        }
        inline void get(int p,int l,int r,int st,int ed){
            if(l==r) return ; int mid=(l+r)>>1; push_down(p,l,r);
            if(st<=mid) get(p<<1,l,mid,st,ed); if(ed>mid) get(p<<1|1,mid+1,r,st,ed); 
            return ;
        } int st,ed,now;
        inline void modify(int p,int l,int r){
            if(st<=l&&r<=ed){
                if(l==r) s[l]=now+'a'-1; else tag[p]=now; return ;
            } int mid=(l+r)>>1; push_down(p,l,r); 
            if(st<=mid) modify(p<<1,l,mid); if(ed>mid) modify(p<<1|1,mid+1,r); return ;
        }
        inline void upd(int l,int r,int c){st=l; ed=r; now=c; return modify(1,1,n);}
    }HT;
    inline bool judge(int st,int len){ if(len==1) return 1;
        rep(i,1,len/2) if(s[st+i-1]!=s[st+len-i]) return 0;
        return 1;
    }
    struct Ans_Seg{
        int tag[N<<2],sum[N<<2];
        inline void push_down(int p,int l,int r){
            int mid=(l+r)>>1; if(tag[p]){
                tag[p<<1]=tag[p<<1|1]=tag[p]; sum[p<<1]=mid-l+1; sum[p<<1|1]=r-mid;
            } tag[p]=0; return ;
        }
        inline int query(int p,int l,int r,int st,int ed){ if(ed<st) return 0;
            if(st<=l&&r<=ed) return sum[p]; int mid=(l+r)>>1,res=0; push_down(p,l,r);
            if(st<=mid) res+=query(p<<1,l,mid,st,ed); if(ed>mid) res+=query(p<<1|1,mid+1,r,st,ed);
            return res;
        }
        inline void push_up(int p){sum[p]=sum[p<<1]+sum[p<<1|1]; return ;}
        inline void cover(int p,int l,int r,int st,int ed){ if(ed<st) return ;
            if(st<=l&&r<=ed) return sum[p]=r-l+1,tag[p]=1,void(); 
            int mid=(l+r)>>1; push_down(p,l,r); 
            if(st<=mid) cover(p<<1,l,mid,st,ed); if(ed>mid) cover(p<<1|1,mid+1,r,st,ed); 
            return push_up(p);
        }
        inline void insert(int p,int l,int r,int pos,int v){
            if(l==r) return sum[p]=v,void(); push_down(p,l,r); int mid=(l+r)>>1; 
            if(pos<=mid) insert(p<<1,l,mid,pos,v); else insert(p<<1|1,mid+1,r,pos,v); 
            return push_up(p);
        }
        int Id;
        inline void rebuild(int p,int l,int r,int st,int ed){
            if(ed<l||ed<st||st>r) return ; if(l==r){if(l+Id-1<=n) sum[p]=judge(l,Id); return ;}
            int mid=(l+r)>>1; if(tag[p]) push_down(p,l,r);
            if(st<=mid) rebuild(p<<1,l,mid,st,ed); if(ed>mid) rebuild(p<<1|1,mid+1,r,st,ed);
            return push_up(p);
        }
    }T[51];
    signed main(){
        scanf("%s",s+1); n=strlen(s+1); k=read(); Q=read();
        for(reg int l=1;l<=k;++l) T[l].Id=l;
        for(reg int l=1;l<=k;++l) T[l].rebuild(1,1,n,1,n);
        while(Q--){
            int opt=read(),l=read(),r=read();
            if(opt==2){
                int up=min(r-l+1,k); ll ans=0;
                rep(i,1,up) ans+=0ll+T[i].query(1,1,n,l,r-i+1);
                print(ans); puts("");
            }else{
                char c; while(!isalpha(c=getchar())); HT.upd(l,r,c-'a'+1);
                HT.get(1,1,n,max(1,l-k+1),min(n,l+k-1));
                HT.get(1,1,n,max(1,r-k+1),min(n,r+k-1));
                rep(i,1,k){
                    T[i].cover(1,1,n,l,r-i+1); 
                    int up=min(r,n-i+1); T[i].rebuild(1,1,n,max(r-i+2,l),up);
                    if(n-i+1<l) T[i].rebuild(1,1,n,max(1,l-i+1),n-i+1);
                    else T[i].rebuild(1,1,n,max(1,l-i+1),l-1);
                }
            }
        } return 0;
    }
}signed main(){return yspm::main();}

最大價值

看看這個部分分設定想到了大力 \(\rm{EK}\) 和模擬費用流,都和正解沒有關係但是啟發是不是代價有凸性

寫了個暴力發現還真能滿足 \(k\) 大小的集合 是 \(k+1\) 大小的集合的子集,那一看就是一個 \(\rm{Insertion}\) 的東西

結果做了一場也沒看出來咋維護,愣沒看出來整差分表

問題寫成 \(\rm{DP}\) 就是 \(\rm{f_{i,j}=\max\{f_{i-1,j},f_{i-1,j-1}+a_i\times (j-1)+b_i\}}\)

如上所說,如果在某個位置 \(k\) 加入一個元素,其對差分表的影響是字尾加 \(a_i\),對應點加 \(a_i(k-1)+b_i\)

,字首不變

式子挺簡單的,按照定義寫出來就有了

那麼按照 \(a_i\) 從小到大排序加入平衡樹即可

$\texttt{Talk is cheap,Show the Code}$
#include<bits/stdc++.h>
using namespace std;
#define reg register
#define int long long
#define pb push_back
#define mp make_pair 
#define Down(i,a,b) for(reg int i=a;i>=b;--i) 
#define rep(i,a,b) for(reg int i=a;i<=b;++i)
template<typename T>inline void ckmin(T &x,T y){x=x<y?x:y; return ;}
template<typename T>inline void ckmax(T &x,T y){x=x<y?y:x; return ;}
namespace yspm{
	inline int read(){
	    int res=0,f=1; char k;
	    while(!isdigit(k=getchar())) if(k=='-') f=-1;
	    while(isdigit(k)) res=res*10+k-'0',k=getchar();
	    return res*f;
    }
    char OPUT[100];
    inline void print(int x){
        if(!x) return putchar('0'),putchar('\n'),void();
        if(x<0) putchar('-'),x=-x; 
        int cnt=0; while(x) OPUT[++cnt]=x%10,x/=10; 
        Down(i,cnt,1) putchar(OPUT[i]+'0'); putchar('\n'); return ;
    } 
    const int N=3e5+10;
    struct node{int a,b;}a[N];
    int val[N],ls[N],rs[N],fa[N],tag[N],siz[N],rt,n,ans[N],cnt;
    inline void push_down(int p){
        if(!tag[p]) return ;
        if(ls[p]) tag[ls[p]]+=tag[p],val[ls[p]]+=tag[p];
        if(rs[p]) tag[rs[p]]+=tag[p],val[rs[p]]+=tag[p];
        tag[p]=0;
        return ;
    }
    inline void push_up(int p){siz[p]=siz[ls[p]]+siz[rs[p]]+1; return ;}
    inline void rotate(int x){
        int y=fa[x],z=fa[y]; if(ls[z]==y) ls[z]=x; else rs[z]=x; 
        if(ls[y]==x) ls[y]=rs[x],fa[rs[x]]=y,rs[x]=y; 
        else rs[y]=ls[x],fa[ls[x]]=y,ls[x]=y; fa[x]=z; fa[y]=x; return push_up(y),push_up(x); 
    }
    inline void splay(int x,int g=0){
        while(fa[x]^g){
            int y=fa[x],z=fa[y]; 
            if(z^g) rotate((ls[z]==y)^(ls[y]==x)?x:y); 
            rotate(x); 
        } if(!g) rt=x; return ;
    }
    inline void insert(int id){
        int fat=0,sum=0,now=rt,sid=0;
        while(now){
            push_down(now); fat=now;
            if(val[now]>(sum+siz[ls[now]])*a[id].a+a[id].b) sid=1,sum+=siz[ls[now]]+1,now=rs[now];
            else sid=0,now=ls[now];
        } 
        fa[id]=fat; val[id]=a[id].a*sum+a[id].b; siz[id]=1;
        if(sid) rs[fa[id]]=id; else ls[fa[id]]=id; splay(id); 
        if(rs[id]) tag[rs[id]]+=a[id].a,val[rs[id]]+=a[id].a;
        return ;
    }
    inline void gans(int x){
        push_down(x);
        if(ls[x]) gans(ls[x]); ans[++cnt]=val[x]; if(rs[x]) gans(rs[x]); return ;
    }
    inline bool cmp(node a,node b){return a.a<b.a;}
	signed main(){
	    n=read(); rep(i,1,n) a[i].a=read(),a[i].b=read(); sort(a+1,a+n+1,cmp);
	    val[1]=a[1].b; rt=1; siz[1]=1; rep(i,2,n) insert(i);
	    gans(rt); rep(i,1,n) print(ans[i]+=ans[i-1]);
	    return 0;
    }
}signed main(){return yspm::main();}
//Use The Time To Enrich This Selfclosing Youth