zoukankan      html  css  js  c++  java
  • 9.8<1>题解

    T1

     我也忘了我考场上在干什么了,好像是在想什么最长链拓扑序之类乱七八糟的东西,所以离正解有十万八千里的距离,现在我也看不懂我当时打了个啥,反正是连了边,用了优先队列,然后WA了

    正解是用线段树优化DP,但是我连DP都没想到,就别提线段树了,先想一下最裸的DP,设$f[i][j]$代表处理完前$i$个水晶,已经选择的水晶中最小的$A$值为$j$的最大摧毁个数,考虑如何转移

    如果$A_i{leq}B_i$那么他只能摧毁炸毁的最小的$A$大于$B_i$的集合炸毁,所以说

    $f[i][A_i]=max(f[i-1][B_i+1],f[i-1][B_i+2],{cdots},f[i-1][maxx])+1$

    如果$A_i>B_i$那么因为$f$数组第二维是最小值,所以最小值如果被更新为$A_i$了,那之前的最小值一定是${geq}A_i$的,所以有

    $f[i][A_i]=max(f[i-1][A_i],f[i-1][A_i+1],f[i-1][A_i+2],{cdots},f[i-1][maxx])+1$

    当然了,也有可能$A_i$对集合中的最小值没有造成影响,那么就是

    $f[i][j]=f[i-1][j]+1$ $j{in}(B_i,A_i)$

    我们发现对$i$的贡献只由对$i-1$的贡献转移而来,取$max$对应了区间求最值,都+1对应了区间加法,对$f[i][A_i]$的修改对应了单点修改,所以把问题移到线段树上就可以了

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<queue>
     5 #define maxn 100100
     6 using namespace std;
     7 struct node{
     8     int zuo,you,w,lan;
     9 }tr[maxn*8];
    10 int n;
    11 int a[maxn],b[maxn],lsh[maxn*2];
    12 void build(int fa,int l,int r)
    13 {
    14     tr[fa].zuo=l;  tr[fa].you=r;
    15     if(l==r)  return ;
    16     int mid=(l+r)>>1;
    17     build(2*fa,l,mid);  build(2*fa+1,mid+1,r);
    18 }
    19 void down(int fa)
    20 {
    21     tr[2*fa].lan+=tr[fa].lan;  tr[2*fa+1].lan+=tr[fa].lan;
    22     tr[2*fa].w+=tr[fa].lan;  tr[2*fa+1].w+=tr[fa].lan;
    23     tr[fa].lan=0;
    24 }
    25 void up(int fa)
    26 {
    27     tr[fa].w=max(tr[2*fa].w,tr[2*fa+1].w);
    28 }
    29 void add(int fa,int l,int r)
    30 {
    31     if(tr[fa].zuo>=l&&tr[fa].you<=r)  {tr[fa].lan++;  tr[fa].w++;  return ;}
    32     if(tr[fa].lan)  down(fa);
    33     int mid=(tr[fa].zuo+tr[fa].you)>>1;
    34     if(l<=mid)  add(2*fa,l,r);
    35     if(r>mid)  add(2*fa+1,l,r);
    36     up(fa);
    37 }
    38 void change(int fa,int pos,int w)
    39 {
    40     if(tr[fa].zuo==tr[fa].you)  {tr[fa].w=max(tr[fa].w,w);  return ;}
    41     int mid=(tr[fa].zuo+tr[fa].you)>>1;
    42     if(tr[fa].lan)  down(fa);
    43     if(pos<=mid)  change(2*fa,pos,w);
    44     else  change(2*fa+1,pos,w);
    45     up(fa);
    46 }
    47 int query(int fa,int l,int r)
    48 {
    49     if(tr[fa].zuo>=l&&tr[fa].you<=r)  return tr[fa].w;
    50     int mid=(tr[fa].zuo+tr[fa].you)>>1,ans=0;
    51     if(tr[fa].lan)  down(fa);
    52     if(l<=mid)  ans=max(ans,query(2*fa,l,r));
    53     if(r>mid)  ans=max(ans,query(2*fa+1,l,r));
    54     return ans;
    55 }
    56 int main()
    57 {
    58 //    freopen("ex_leader2.in","r",stdin);
    59     scanf("%d",&n);
    60     for(int i=1;i<=n;++i)  {scanf("%d%d",&a[i],&b[i]);  lsh[i]=a[i];  lsh[i+n]=b[i];}
    61     sort(lsh+1,lsh+2*n+1);
    62     int len=unique(lsh+1,lsh+2*n+1)-lsh-1;
    63     for(int i=1;i<=n;++i)
    64     {
    65         a[i]=lower_bound(lsh+1,lsh+len+1,a[i])-lsh;
    66         b[i]=lower_bound(lsh+1,lsh+len+1,b[i])-lsh;
    67     }
    68     build(1,1,len);
    69     for(int i=1;i<=n;++i)
    70     {
    71         if(a[i]<=b[i])  {int chan=query(1,b[i]+1,len)+1;  change(1,a[i],chan);}
    72         else  {add(1,b[i]+1,a[i]);  int chan=query(1,a[i]+1,len)+1;  change(1,a[i],chan);}
    73     }
    74     printf("%d
    ",tr[1].w);
    75     return 0;
    76 }
    View Code

    T2

    启发式合并or线段树合并,当时不想打数据结构,所以咕到现在

    T3

    考场上想到了一毛一样的dp定义,最后死在了对答案的容斥上,出现本质相同的子序列,一定是有一个字母出现了第二边导致本质相同,那就找到前面第一个和当前相同的字母,然后刨掉和那个字母相同的就可以了

    设$dp[i][j]$代表以第$i$个位置为结尾的长度为$j$的本质不同的串有多少个,会重复的就是以前面的相同字母结束的串,所以$dp[i][j]=dp[i-1][j]+dp[i-1][j-1]-dp[las-1][j-1]$,注意一下数组越界的问题,可能会死

     1 #include<iostream>
     2 #include<cstring>
     3 #include<string>
     4 #include<cstdio>
     5 #define ll long long
     6 #define mod 998244353
     7 #define maxn 3030
     8 using namespace std;
     9 int len,cd,flag;
    10 int pos[30];
    11 char s[3010];
    12 ll f[maxn][maxn];
    13 int main()
    14 {
    15 //    freopen("coin.in","r",stdin);
    16     scanf("%s%d",s+1,&len);  cd=strlen(s+1);
    17     for(int i=2;i<=cd;++i)
    18         if(s[i]!=s[i-1])  {flag=1;  break;}
    19     if(!flag)  {printf("1
    ");  return 0;}
    20     else
    21     {
    22         for(int i=1;i<=cd;++i)
    23         {
    24             if(pos[s[i]-'a']==0)  f[i][1]=f[i-1][1]+1;
    25             else  f[i][1]=f[i-1][1];
    26             for(int j=2;j<=min(i,len);++j)
    27             {
    28                 if(pos[s[i]-'a']!=0)
    29                     f[i][j]=((f[i-1][j]+f[i-1][j-1])%mod-f[pos[s[i]-'a']-1][j-1]+mod)%mod;
    30                 else
    31                     f[i][j]=(f[i-1][j]+f[i-1][j-1])%mod;
    32             }
    33             pos[s[i]-'a']=i;
    34         }
    35     }
    36     printf("%lld
    ",f[cd][len]);
    37     return 0;
    38 }
    View Code
  • 相关阅读:
    ES6、ES7、ES8特性
    【react】XXX项目环境搭建
    map
    vector
    list
    米勒素数模板
    POJ-2421-Constructing Roads(最小生成树 普利姆)
    HDU1301 Jungle Roads(Kruskal)
    Truck History(prime)
    phpstorm快捷键和激活
  • 原文地址:https://www.cnblogs.com/hzjuruo/p/11611364.html
Copyright © 2011-2022 走看看