省选模拟七 题解

写在前面:

这次考试的策略还是蛮正确的

发现了$T2$是水题后先开了$T3$的$60pts$暴力

剩下时间连打带调外加考场刚好用完时间

但可惜的是$T1dp$求两点之间最小代价由于转移出环被弃掉了

其实用$bfs$求最小代价就可以$AC$了

实力不济

就没什么好说的

A. 翻转硬币

标签:

$bfs+$状压$dp$

题解:

先对序列差分

问题转化为每次可以同时异或两个点,求最小代价

同时消去两个点的代价可以用$bfs$预处理出来

源点的个数就是差分序列的$1$的个数

有了这个,状态便有了明显的层次性了

$k<=10$,也就是说点数$<=20$

直接状压$dp$即可

复杂度$O(2*k*n+(2*k)^2*2^{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 }
T1

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 }
T2

我的暴力循环边界其实是瞎写的,反正$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 }
T3

猜你喜欢

转载自www.cnblogs.com/AthosD/p/12193079.html