省选模拟七 题解
写在前面:
这次考试的策略还是蛮正确的
发现了$T2$是水题后先开了$T3$的$60pts$暴力
剩下时间连打带调外加考场刚好用完时间
但可惜的是$T1dp$求两点之间最小代价由于转移出环被弃掉了
其实用$bfs$求最小代价就可以$AC$了
实力不济
就没什么好说的
A. 翻转硬币
标签:
$bfs+$状压$dp$
题解:
先对序列差分
问题转化为每次可以同时异或两个点,求最小代价
同时消去两个点的代价可以用$bfs$预处理出来
源点的个数就是差分序列的$1$的个数
有了这个,状态便有了明显的层次性了
$k<=10$,也就是说点数$<=20$
直接状压$dp$即可
复杂度$O(2kn+(2k)^22^{2*k})$
其实每次只需要钦定消去最小点
复杂度$O(2kn+2k2^{2*k})$
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=1e4+10,INF=1e9; 4 int cnt,n,k,m,dp[1<<20],b[N],a[N],id[N],dis[21][N]; 5 void bfs(int S) 6 { 7 memset(dis[S],-1,sizeof(dis[S])); 8 queue<int>q; 9 q.push(id[S]); 10 dis[S][id[S]]=0; 11 while(q.size()) 12 { 13 int x=q.front(); 14 q.pop(); 15 for(int i=1;i<=m;i++) 16 { 17 int y=x+a[i]; 18 if(y<=n+1&&dis[S][y]==-1) 19 { 20 dis[S][y]=dis[S][x]+1; 21 q.push(y); 22 } 23 y-=a[i]*2; 24 if(y>0&&dis[S][y]==-1) 25 { 26 dis[S][y]=dis[S][x]+1; 27 q.push(y); 28 } 29 } 30 } 31 } 32 int dfs(int x) 33 { 34 if(!x) return 0; 35 if(dp[x]!=INF) return dp[x]; 36 for(int i=0;i<cnt;i++) 37 { 38 if(!(x&(1<<i))) continue; 39 for(int j=0;j<cnt;j++) 40 { 41 if(i==j) continue; 42 if(!(x&(1<<j))) continue; 43 if(dis[i+1][id[j+1]]==-1) continue; 44 dp[x]=min(dp[x],dfs(x^(1<<i)^(1<<j))+dis[i+1][id[j+1]]); 45 } 46 } 47 return dp[x]; 48 } 49 int main() 50 { 51 //freopen("1.in","r",stdin); 52 //freopen("1.out","w",stdout); 53 scanf("%d%d%d",&n,&k,&m); 54 for(int i=1,x;i<=k;i++) scanf("%d",&x),b[x]^=1,b[x+1]^=1; 55 for(int i=1;i<=m;i++) scanf("%d",&a[i]); 56 for(int i=1;i<=n+1;i++) 57 { 58 if(b[i]) 59 { 60 id[++cnt]=i; 61 bfs(cnt); 62 } 63 } 64 for(int i=0;i<(1<<cnt);i++) dp[i]=INF; 65 dfs((1<<cnt)-1); 66 dp[(1<<cnt)-1]=dp[(1<<cnt)-1]>=INF?-1:dp[(1<<cnt)-1]; 67 printf("%d\n",dp[(1<<cnt)-1]); 68 return 0; 69 }
B. 回文子串
标签:
线段树
题解:
$k<=50$
边界暴力修改
中间的贡献都是一样的,可以用线段树区间修改
复杂度$O(m*k^2)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=5e4+10; 4 int S,ans,n,k,m; 5 char s[N],t[5]; 6 struct SGT 7 { 8 #define ls k<<1 9 #define rs k<<1|1 10 int L[N*4],R[N*4],w[N*4],f[N*4]; 11 char q[N*4]; 12 void down(int k) 13 { 14 w[ls]=(R[ls]-L[ls]+1)*f[k]; 15 q[ls]=q[k]; 16 w[rs]=(R[rs]-L[rs]+1)*f[k]; 17 q[rs]=q[k]; 18 f[ls]=f[rs]=f[k]; 19 f[k]=-1; 20 } 21 void build(int k,int l,int r) 22 { 23 L[k]=l,R[k]=r; 24 f[k]=-1; 25 if(l==r) 26 { 27 q[k]=s[l]; 28 return; 29 } 30 int mid=(l+r)>>1; 31 build(ls,l,mid); 32 build(rs,mid+1,r); 33 } 34 void change(int k,int l,int r,int x,char y) 35 { 36 if(L[k]>=l&&R[k]<=r) 37 { 38 w[k]=x*(R[k]-L[k]+1); 39 f[k]=x; 40 q[k]=y; 41 return; 42 } 43 if(f[k]!=-1) down(k); 44 int mid=(L[k]+R[k])>>1; 45 if(l<=mid) change(ls,l,r,x,y); 46 if(r>mid) change(rs,l,r,x,y); 47 w[k]=w[ls]+w[rs]; 48 } 49 int query(int k,int l,int r) 50 { 51 if(L[k]>=l&&R[k]<=r) return w[k]; 52 if(f[k]!=-1) down(k); 53 int mid=(L[k]+R[k])>>1,sum=0; 54 if(l<=mid) sum+=query(ls,l,r); 55 if(r>mid) sum+=query(rs,l,r); 56 return sum; 57 } 58 char get(int k,int x) 59 { 60 if(L[k]==R[k]) return q[k]; 61 if(f[k]!=-1) down(k); 62 int mid=(L[k]+R[k])>>1; 63 if(x<=mid) return get(ls,x); 64 else return get(rs,x); 65 } 66 void clear(int k,int x,char y) 67 { 68 if(L[k]==R[k]) 69 { 70 q[k]=y; 71 return; 72 } 73 if(f[k]!=-1) down(k); 74 int mid=(L[k]+R[k])>>1; 75 if(x<=mid) clear(ls,x,y); 76 else clear(rs,x,y); 77 } 78 }T; 79 void update(int x) 80 { 81 int L,R,ans=0; 82 L=R=x; 83 while(L>=1&&R<=n&&s[L]==s[R]&&R-L+1<=k) L--,R++,ans++; 84 L=x,R=x+1; 85 while(L>=1&&R<=n&&s[L]==s[R]&&R-L+1<=k) L--,R++,ans++; 86 T.change(1,x,x,ans,T.get(1,x)); 87 } 88 int get(int l,int r,int x) 89 { 90 int L,R,ans=0; 91 L=R=x; 92 while(L>=l&&R<=r&&s[L]==s[R]&&R-L+1<=k) L--,R++,ans++; 93 L=x,R=x+1; 94 while(L>=l&&R<=r&&s[L]==s[R]&&R-L+1<=k) L--,R++,ans++; 95 return ans; 96 } 97 int main() 98 { 99 //freopen("2.in","r",stdin); 100 //freopen("2.out","w",stdout); 101 scanf("%s%d%d",s+1,&k,&m); 102 n=strlen(s+1); 103 T.build(1,1,n); 104 for(int i=1;i<=n;i++) update(i); 105 S=(k+1)/2; 106 for(int i=1,opt,l,r;i<=m;i++) 107 { 108 scanf("%d%d%d",&opt,&l,&r); 109 if(opt==1) 110 { 111 scanf("%s",t); 112 if(l+S+1>r-S-1) 113 { 114 for(int j=l;j<=r;j++) T.clear(1,j,t[0]); 115 for(int j=max(1,l-S-k-1);j<=min(n,r+k+S+1);j++) s[j]=T.get(1,j); 116 for(int j=max(1,l-S);j<=min(n,r+S);j++) update(j); 117 } 118 else 119 { 120 T.change(1,l+S+1,r-S-1,(k+1)/2+k/2,t[0]); 121 for(int j=l;j<=min(r-S-1,l+S);j++) T.clear(1,j,t[0]); 122 for(int j=max(l,r-S);j<=r;j++) T.clear(1,j,t[0]); 123 for(int j=max(1,l-S-k-1);j<=min(n,min(r-1,l+k+1+S));j++) s[j]=T.get(1,j); 124 for(int j=max(1,r-S-k);j<=min(n,r+S+1+k);j++) s[j]=T.get(1,j); 125 for(int j=max(1,l-S);j<=min(r-S-1,l+S);j++) update(j); 126 for(int j=max(1,r-S);j<=min(n,r+S);j++) update(j); 127 } 128 } 129 else 130 { 131 ans=0; 132 if(l+S>r) 133 { 134 for(int j=max(1,l-k);j<=min(n,r+k);j++) s[j]=T.get(1,j); 135 for(int j=l;j<=r;j++) ans+=get(l,r,j); 136 } 137 else 138 { 139 ans=l+S+1<=r-S-1?T.query(1,l+S+1,r-S-1):0; 140 for(int j=max(1,l-S);j<=min(r-1,l+S+S);j++) s[j]=T.get(1,j); 141 for(int j=max(1,max(l-k,r-S-k));j<=min(n,r+k);j++) s[j]=T.get(1,j); 142 for(int j=l;j<=min(r-S-1,l+S);j++) ans+=get(l,r,j); 143 for(int j=max(l,r-S);j<=r;j++) ans+=get(l,r,j); 144 } 145 printf("%d\n",ans); 146 } 147 } 148 return 0; 149 }
我的暴力循环边界其实是瞎写的,反正$4s$能跑过
C. 最大价值
标签:
平衡树优化$dp$
题解:
设$f[i][j]$代表考虑了$i$个点已经取了$j$个点的最大收益
有:
$$f[i][j]=max(f[i-1][j],f[i-1][j-1]+(j-1)*a[i]+b[i])$$
可以归纳打表证明出$f$的转移点是单调的
设
$$g[i][j]=f[i][j]-f[i][j-1]$$
x为第一个从后面转移的点
那么
$$j\in[1,x-1]\ g[i][j]=g[i-1][j]$$
$$j=x\ g[i][j]=(j-1)*a_i+b_i$$
$$j\in[x,i]\ g[i][j]=g[i-1][j-1]+a[i]$$
平衡树维护即可
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int N=3e5+10; 5 int n,g[N]; 6 struct node 7 { 8 int a,b; 9 friend bool operator <(node l,node r) 10 { 11 return l.a<r.a; 12 } 13 }f[N]; 14 int read() 15 { 16 int sum,k=1;char s; 17 while(s=getchar(),s<'0'||s>'9') if(s=='-') k=-1;sum=s-'0'; 18 while(s=getchar(),s>='0'&&s<='9') sum=sum*10+s-'0'; 19 return k*sum; 20 } 21 struct Splay 22 { 23 int cnt,root,st[N],ch[N][2],f[N],w[N],size[N],lazy[N]; 24 void pushup(int x) 25 { 26 size[x]=size[ch[x][0]]+size[ch[x][1]]+1; 27 } 28 void pushdown(int x) 29 { 30 if(ch[x][0]) w[ch[x][0]]+=lazy[x],lazy[ch[x][0]]+=lazy[x]; 31 if(ch[x][1]) w[ch[x][1]]+=lazy[x],lazy[ch[x][1]]+=lazy[x]; 32 lazy[x]=0; 33 } 34 int get(int x) 35 { 36 return ch[f[x]][1]==x; 37 } 38 void rotate(int x) 39 { 40 int y=f[x],z=f[y],k=get(x),w=ch[x][k^1]; 41 ch[y][k]=w;if(w) f[w]=y; 42 if(z) ch[z][ch[z][1]==y]=x;f[x]=z; 43 ch[x][k^1]=y;f[y]=x; 44 pushup(y),pushup(x); 45 } 46 void splay(int x,int goal) 47 { 48 int top=0,y=x; 49 while(y^goal) st[++top]=y,y=f[y]; 50 while(top) pushdown(st[top--]); 51 while(f[x]^goal) 52 { 53 int y=f[x],z=f[y]; 54 if(z^goal) rotate(get(x)^get(y)?x:y); 55 rotate(x); 56 } 57 if(!goal) root=x; 58 } 59 void insert(int x,int y,int z,int typ) 60 { 61 w[++cnt]=z; 62 size[cnt]=1; 63 if(x) size[x]++; 64 size[y]++; 65 ch[y][typ]=cnt; 66 f[cnt]=y; 67 splay(cnt,0); 68 } 69 int kth(int x) 70 { 71 int now=root; 72 while(1) 73 { 74 pushdown(now); 75 if(x<=size[ch[now][0]]) now=ch[now][0]; 76 else if(x==size[ch[now][0]]+1) break; 77 else x-=size[ch[now][0]]+1,now=ch[now][1]; 78 } 79 splay(now,0); 80 return now; 81 } 82 int calc(int x,int y,int z) 83 { 84 int now=root,rk=size[ch[now][0]]+1,ans=x,fa=0; 85 while(now) 86 { 87 int val=(rk-1)*y+z; 88 pushdown(now); 89 if(w[now]<val) 90 { 91 ans=min(ans,rk); 92 fa=now; 93 now=ch[now][0],rk-=size[ch[now][1]]+1; 94 } 95 else fa=now,now=ch[now][1],rk+=size[ch[now][0]]+1; 96 } 97 splay(fa,0); 98 return ans; 99 } 100 }S; 101 signed main() 102 { 103 //freopen("1.in","r",stdin); 104 //freopen("1.out","w",stdout); 105 n=read(); 106 for(int i=1;i<=n;i++) f[i].a=read(),f[i].b=read(); 107 sort(f+1,f+n+1); 108 S.root=S.cnt=S.size[1]=1; 109 S.w[1]=f[1].b; 110 for(int i=2,L;i<=n;i++) 111 { 112 L=S.calc(i,f[i].a,f[i].b); 113 if(L==i) 114 { 115 int x=S.kth(L-1); 116 S.splay(x,0); 117 S.insert(0,x,f[i].a*(L-1)+f[i].b,1); 118 } 119 else 120 { 121 int x=L==1?0:S.kth(L-1),y=S.kth(L); 122 if(x) S.splay(x,0); 123 S.splay(y,x); 124 S.w[y]+=f[i].a; 125 S.lazy[y]+=f[i].a; 126 S.pushdown(y); 127 S.insert(x,y,f[i].a*(L-1)+f[i].b,0); 128 } 129 } 130 for(int i=1;i<=n;i++) g[i]=S.w[S.kth(i)]; 131 for(int i=1;i<=n;i++) g[i]+=g[i-1]; 132 for(int i=1;i<=n;i++) printf("%lld\n",g[i]); 133 return 0; 134 }