「考試總結2021-08-12」 模擬3
阿新 • • 發佈:2021-08-13
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