• 省选模拟七 题解


    写在前面:

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

    发现了$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
    ",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
    ",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为第一个从后面转移的点

    那么

    $$jin[1,x-1] g[i][j]=g[i-1][j]$$

    $$j=x g[i][j]=(j-1)*a_i+b_i$$

    $$jin[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
    ",g[i]);
    133         return 0;
    134 }
    T3
  • 相关阅读:
    麻省理工算法导论学习笔记(1)算法介绍
    麻省理工算法导论学习笔记(2)渐近符号、递归及解法
    Mybatis if 标签 判断不生效
    Linux permission denied解决方法?
    MySQL查找是否存在
    List集合数据去重
    Java获取list集合的前几个元素
    git如何新建(修改)分支
    asp.net下url参数含有中文读取后为乱码
    时间复杂度为O(n)的排序算法
  • 原文地址:https://www.cnblogs.com/AthosD/p/12193079.html
Copyright © 2020-2023  润新知