8.1题解

下午有点不舒服,这个人状态都不好了,一道破题,两个zz错误搞了一下午,刚刚水了道题,几年前的NOIP真水

T1

怎么说呢,暴力40,跟排序那道题有点像,线段树维护01串,二分答案,不过这道题,某Larry实测,n遍二分,T到飞,正解嘛。着实和那道题有点像,那道题是线段树维护1的个数,也就是区间和,排序通过区间覆盖实现,这道题的话,线段树维护每个区间中26个字母出现的次数,dalao讲题的时候说用桶,我无比懵逼,结果不就是数组维护字母出现的个数嘛,说的倒挺高大上,可能还是我太弱了叭,然后进行覆盖,之后输出的时候搜到底输出即可,不过出题人卡常真心恶心,正解T90?for循环展开就A了,实属稍恶心

  1 #include<iostream>
  2 #include<cstdio>
  3 #define maxn 100100
  4 #define maxx 28
  5 using namespace std;
  6 struct node{
  7     int zuo,you;
  8     int tong[maxx],lan;
  9 }s[maxn*4],cun;
 10 int n,m;
 11 int a[maxn];
 12 char aa[maxn];
 13 inline void mem(int f)
 14 {
 15     for(int i=1;i<=26;++i)  s[f].tong[i]=0;
 16 }
 17 inline void up(int f)
 18 {
 19     for(int i=1;i<=26;++i)  s[f].tong[i]=s[2*f].tong[i]+s[2*f+1].tong[i];
 20 }
 21 inline void down(int f)
 22 {
 23     if(s[f].zuo==s[f].you)  return ;
 24     if(s[f].lan)
 25     {
 26         int ls=s[f].lan;
 27         mem(2*f);  mem(2*f+1);
 28         s[2*f].tong[ls]=s[2*f].you-s[2*f].zuo+1;
 29         s[2*f+1].tong[ls]=s[2*f+1].you-s[2*f+1].zuo+1;
 30         s[2*f].lan=ls;  s[2*f+1].lan=ls;  s[f].lan=0;
 31     }
 32 }
 33 inline void build(int f,int l,int r)
 34 {
 35     s[f].zuo=l;  s[f].you=r;
 36     if(l==r)  {s[f].tong[a[l]]++;  return ;}
 37     int mid=(s[f].zuo+s[f].you)>>1;
 38     build(2*f,l,mid);  build(2*f+1,mid+1,r);
 39     up(f);
 40 }
 41 inline void quary(int f,int l,int r)
 42 {
 43     if(s[f].zuo>=l&&s[f].you<=r)
 44     {
 45         for(int i=1;i<=26;++i)  cun.tong[i]+=s[f].tong[i];
 46         return ;
 47     }
 48     down(f);
 49     int mid=(s[f].zuo+s[f].you)>>1;
 50     if(l<=mid)  quary(2*f,l,r);
 51     if(r>mid)  quary(2*f+1,l,r);
 52 }
 53 inline void change(int f,int l,int r,int w)
 54 {
 55     if(s[f].zuo>=l&&s[f].you<=r)
 56     {
 57         mem(f);  s[f].tong[w]=s[f].you-s[f].zuo+1;
 58         s[f].lan=w;  return ;
 59     }
 60     down(f);
 61     int mid=(s[f].zuo+s[f].you)>>1;
 62     if(l<=mid)  change(2*f,l,r,w);
 63     if(r>mid)  change(2*f+1,l,r,w);
 64     up(f);
 65 }
 66 inline void out(int f)
 67 {
 68     char ans;
 69     if(s[f].zuo==s[f].you)
 70     {
 71         for(int i=1;i<=26;++i)
 72             if(s[f].tong[i])  ans=i-1+'a';
 73         printf("%c",ans);
 74         return ;
 75     }
 76     down(f);  out(2*f);  out(2*f+1);
 77 }
 78 int main()
 79 {
 80     scanf("%d%d",&n,&m);  scanf("%s",aa+1);
 81     for(int i=1;i<=n;++i)  a[i]=aa[i]-'a'+1;
 82     build(1,1,n);
 83     for(int i=1;i<=m;++i)
 84     {
 85         int l,r,x;  scanf("%d%d%d",&l,&r,&x);
 86         for(int i=1;i<=26;++i)  cun.tong[i]=0;
 87         quary(1,l,r);
 88         if(x==0)
 89         {
 90             int js=l;
 91             for(int i=26;i>=1;--i)
 92                 if(cun.tong[i])  {change(1,js,js+cun.tong[i]-1,i);  js+=cun.tong[i];}
 93         }
 94         else
 95         {
 96             int js=l;
 97             for(int i=1;i<=26;++i)
 98                 if(cun.tong[i])  {change(1,js,js+cun.tong[i]-1,i);  js+=cun.tong[i];}
 99         }
100     }
101     out(1);  puts("");
102     return 0;
103 }
T90
  1 #include<iostream>
  2 #include<cstdio>
  3 #define maxn 100100
  4 #define maxx 28
  5 using namespace std;
  6 struct node{
  7     int zuo,you;
  8     int tong[maxx],lan;
  9 }s[maxn*4],cun;
 10 int n,m;
 11 int a[maxn];
 12 char aa[maxn];
 13 inline void mem(int f)
 14 {
 15     s[f].tong[1]=0;  s[f].tong[2]=0;  s[f].tong[3]=0;
 16     s[f].tong[4]=0;  s[f].tong[5]=0;  s[f].tong[6]=0;
 17     s[f].tong[7]=0;  s[f].tong[8]=0;  s[f].tong[9]=0;
 18     s[f].tong[10]=0;  s[f].tong[11]=0;  s[f].tong[12]=0;
 19     s[f].tong[13]=0;  s[f].tong[14]=0;  s[f].tong[15]=0;
 20     s[f].tong[16]=0;  s[f].tong[17]=0;  s[f].tong[18]=0;
 21     s[f].tong[19]=0;  s[f].tong[20]=0;  s[f].tong[21]=0;
 22     s[f].tong[22]=0;  s[f].tong[23]=0;  s[f].tong[24]=0;
 23     s[f].tong[25]=0;  s[f].tong[26]=0;
 24 }
 25 inline void up(int f)
 26 {
 27     s[f].tong[1]=s[2*f].tong[1]+s[2*f+1].tong[1];
 28     s[f].tong[2]=s[2*f].tong[2]+s[2*f+1].tong[2];
 29     s[f].tong[3]=s[2*f].tong[3]+s[2*f+1].tong[3];
 30     s[f].tong[4]=s[2*f].tong[4]+s[2*f+1].tong[4];
 31     s[f].tong[5]=s[2*f].tong[5]+s[2*f+1].tong[5];
 32     s[f].tong[6]=s[2*f].tong[6]+s[2*f+1].tong[6];
 33     s[f].tong[7]=s[2*f].tong[7]+s[2*f+1].tong[7];
 34     s[f].tong[8]=s[2*f].tong[8]+s[2*f+1].tong[8];
 35     s[f].tong[9]=s[2*f].tong[9]+s[2*f+1].tong[9];
 36     s[f].tong[10]=s[2*f].tong[10]+s[2*f+1].tong[10];
 37     s[f].tong[11]=s[2*f].tong[11]+s[2*f+1].tong[11];
 38     s[f].tong[12]=s[2*f].tong[12]+s[2*f+1].tong[12];
 39     s[f].tong[13]=s[2*f].tong[13]+s[2*f+1].tong[13];
 40     s[f].tong[14]=s[2*f].tong[14]+s[2*f+1].tong[14];
 41     s[f].tong[15]=s[2*f].tong[15]+s[2*f+1].tong[15];
 42     s[f].tong[16]=s[2*f].tong[16]+s[2*f+1].tong[16];
 43     s[f].tong[17]=s[2*f].tong[17]+s[2*f+1].tong[17];
 44     s[f].tong[18]=s[2*f].tong[18]+s[2*f+1].tong[18];
 45     s[f].tong[19]=s[2*f].tong[19]+s[2*f+1].tong[19];
 46     s[f].tong[20]=s[2*f].tong[20]+s[2*f+1].tong[20];
 47     s[f].tong[21]=s[2*f].tong[21]+s[2*f+1].tong[21];
 48     s[f].tong[22]=s[2*f].tong[22]+s[2*f+1].tong[22];
 49     s[f].tong[23]=s[2*f].tong[23]+s[2*f+1].tong[23];
 50     s[f].tong[24]=s[2*f].tong[24]+s[2*f+1].tong[24];
 51     s[f].tong[25]=s[2*f].tong[25]+s[2*f+1].tong[25];
 52     s[f].tong[26]=s[2*f].tong[26]+s[2*f+1].tong[26];
 53 }
 54 inline void down(int f)
 55 {
 56     if(s[f].zuo==s[f].you)  return ;
 57     if(s[f].lan)
 58     {
 59         int ls=s[f].lan;
 60         mem(2*f);  mem(2*f+1);
 61         s[2*f].tong[ls]=s[2*f].you-s[2*f].zuo+1;
 62         s[2*f+1].tong[ls]=s[2*f+1].you-s[2*f+1].zuo+1;
 63         s[2*f].lan=ls;  s[2*f+1].lan=ls;  s[f].lan=0;
 64     }
 65 }
 66 inline void build(int f,int l,int r)
 67 {
 68     s[f].zuo=l;  s[f].you=r;
 69     if(l==r)  {s[f].tong[a[l]]++;  return ;}
 70     int mid=(s[f].zuo+s[f].you)>>1;
 71     build(2*f,l,mid);  build(2*f+1,mid+1,r);
 72     up(f);
 73 }
 74 inline void quary(int f,int l,int r)
 75 {
 76     if(s[f].zuo>=l&&s[f].you<=r)
 77     {
 78         cun.tong[1]+=s[f].tong[1];
 79         cun.tong[2]+=s[f].tong[2];
 80         cun.tong[3]+=s[f].tong[3];
 81         cun.tong[4]+=s[f].tong[4];
 82         cun.tong[5]+=s[f].tong[5];
 83         cun.tong[6]+=s[f].tong[6];
 84         cun.tong[7]+=s[f].tong[7];
 85         cun.tong[8]+=s[f].tong[8];
 86         cun.tong[9]+=s[f].tong[9];
 87         cun.tong[10]+=s[f].tong[10];
 88         cun.tong[11]+=s[f].tong[11];
 89         cun.tong[12]+=s[f].tong[12];
 90         cun.tong[13]+=s[f].tong[13];
 91         cun.tong[14]+=s[f].tong[14];
 92         cun.tong[15]+=s[f].tong[15];
 93         cun.tong[16]+=s[f].tong[16];
 94         cun.tong[17]+=s[f].tong[17];
 95         cun.tong[18]+=s[f].tong[18];
 96         cun.tong[19]+=s[f].tong[19];
 97         cun.tong[20]+=s[f].tong[20];
 98         cun.tong[21]+=s[f].tong[21];
 99         cun.tong[22]+=s[f].tong[22];
100         cun.tong[23]+=s[f].tong[23];
101         cun.tong[24]+=s[f].tong[24];
102         cun.tong[25]+=s[f].tong[25];
103         cun.tong[26]+=s[f].tong[26];
104         return ;
105     }
106     down(f);
107     int mid=(s[f].zuo+s[f].you)>>1;
108     if(l<=mid)  quary(2*f,l,r);
109     if(r>mid)  quary(2*f+1,l,r);
110 }
111 inline void change(int f,int l,int r,int w)
112 {
113     if(s[f].zuo>=l&&s[f].you<=r)
114     {
115         mem(f);  s[f].tong[w]=s[f].you-s[f].zuo+1;
116         s[f].lan=w;  return ;
117     }
118     down(f);
119     int mid=(s[f].zuo+s[f].you)>>1;
120     if(l<=mid)  change(2*f,l,r,w);
121     if(r>mid)  change(2*f+1,l,r,w);
122     up(f);
123 }
124 inline void out(int f)
125 {
126     char ans;
127     if(s[f].zuo==s[f].you)
128     {
129         if(s[f].tong[1])  ans=1-1+'a';
130         if(s[f].tong[2])  ans=2-1+'a';
131         if(s[f].tong[3])  ans=3-1+'a';
132         if(s[f].tong[4])  ans=4-1+'a';
133         if(s[f].tong[5])  ans=5-1+'a';
134         if(s[f].tong[6])  ans=6-1+'a';
135         if(s[f].tong[7])  ans=7-1+'a';
136         if(s[f].tong[8])  ans=8-1+'a';
137         if(s[f].tong[9])  ans=9-1+'a';
138         if(s[f].tong[10])  ans=10-1+'a';
139         if(s[f].tong[11])  ans=11-1+'a';
140         if(s[f].tong[12])  ans=12-1+'a';
141         if(s[f].tong[13])  ans=13-1+'a';
142         if(s[f].tong[14])  ans=14-1+'a';
143         if(s[f].tong[15])  ans=15-1+'a';
144         if(s[f].tong[16])  ans=16-1+'a';
145         if(s[f].tong[17])  ans=17-1+'a';
146         if(s[f].tong[18])  ans=18-1+'a';
147         if(s[f].tong[19])  ans=19-1+'a';
148         if(s[f].tong[20])  ans=20-1+'a';
149         if(s[f].tong[21])  ans=21-1+'a';
150         if(s[f].tong[22])  ans=22-1+'a';
151         if(s[f].tong[23])  ans=23-1+'a';
152         if(s[f].tong[24])  ans=24-1+'a';
153         if(s[f].tong[25])  ans=25-1+'a';
154         if(s[f].tong[26])  ans=26-1+'a';
155         printf("%c",ans);
156         return ;
157     }
158     down(f);  out(2*f);  out(2*f+1);
159 }
160 int main()
161 {
162     scanf("%d%d",&n,&m);  scanf("%s",aa+1);
163     for(int i=1;i<=n;++i)  a[i]=aa[i]-'a'+1;
164     build(1,1,n);
165     for(int i=1;i<=m;++i)
166     {
167         int l,r,x;  scanf("%d%d%d",&l,&r,&x);
168         for(int i=1;i<=26;++i)  cun.tong[i]=0;
169         quary(1,l,r);
170         if(x==0)
171         {
172             int js=l;
173             for(int i=26;i>=1;--i)
174                 if(cun.tong[i])  {change(1,js,js+cun.tong[i]-1,i);  js+=cun.tong[i];}
175         }
176         else
177         {
178             int js=l;
179             for(int i=1;i<=26;++i)
180                 if(cun.tong[i])  {change(1,js,js+cun.tong[i]-1,i);  js+=cun.tong[i];}
181         }
182     }
183     out(1);  puts("");
184     return 0;
185 }
前方AC代码,请做好心理准备

那个懒标记我一开始记麻烦了,就不误导大家了,不过在线段树中懒标记确实很重要,做题的时候最好仔细思考一下懒标记为什么这么记,以及这么记带来的效果和便利是什么

T2

一道脑回路清奇的dp题,是道拓宽思路的好题,光dp定义,我就理解了很久,wjn考场AC,属实nb,上题解

设$dp[i][j]$代表当前处理到第$i$列,有$j$个右区间的左端点在第$i$列及其以左,放置了1,也就是放了$j$个1,不过是右区间中的$j$个,要不换个说法?有$j$个右区间在第$i$列及其以左放了1,emm大概是这样了,这样的话dp转移就由传统的按行或按格转移,变为了按列转移,状态转移的话我们先考虑那个乱入的右区间

$do[i][j]+=dp[i-1][j]$

这个就是不放一,很好理解

$do[i][j]+=dp[i-1][j-1]*[r[i]-(j-1)]$

补充数组定义,$l[i]$表示左区间在$i$$i$列以左的区间总数,也就是前缀和,$r[i]$同理,代表右区间在$i$列及其以左的区间总数,依旧前缀和,这个都计算$i$及其以左的前缀和的原因其实还挺好理解的,毕竟你在从左向右转移嘛,$dp[i-1][j-1]$就是要在前i列再放一个1,$r[i]-(j-1)$就是现在可以放一的区间个数

所以就是一个放1,一个不放1两种情况

接下来处理左区间,先上式子吧,$dp[i][j]=dp[i][j]*A_{i-j-l[i-1]}^{l[i]-l[i-1]}$,关于这个排列数,其实就是你现在一共有$i-j-l[i-1]$个位置可以放1,而你需要放$l[i]-l[i-1]$个一,那为什么不是组合数是排列数呢?举个例子,一共要选$x$列放1,其中对于第$p$行和第$q$行,你都在第$o$列放一,当然不是同一种情况,感性理解一下,当然就是排列数

这道题很拓宽思路,以后又可以有一种新的思路

 1 #include<iostream>
 2 #include<cstdio>
 3 #define maxn 3010
 4 #define mod 998244353
 5 #define int long long
 6 using namespace std;
 7 int n,m;
 8 int zuo[maxn]/*左区间端点个数前缀和*/,you[maxn]/*右区间端点个数前缀和*/,jc[maxn],ny[maxn];
 9 int f[maxn][maxn];//右区间的左端点在第i列及其以左,已经放了j个1
10 int ksm(int a,int b,int c)
11 {
12     int ans=1;  a=a%mod;
13     while(b)
14     {
15         if(b&1)  ans=(ans*a)%mod;
16         b=b>>1;  a=(a*a)%mod;
17     }
18     return ans%mod;
19 }
20 int A(int x,int y)
21 {
22     if(x<0)  return 1ll*0;
23     if(y<0)  return 1ll*0;
24     if(x<y)  return 1ll*0;
25     if(y==0)  return 1ll*1;
26     return (jc[x]*ny[x-y])%mod;
27 }
28 signed main()
29 {
30     scanf("%lld%lld",&n,&m);
31     jc[0]=1;
32     int ls=max(n,m);
33     for(int i=1;i<=ls;++i)  jc[i]=(jc[i-1]*i)%mod;
34     ny[ls]=ksm(jc[ls],mod-2,mod);
35     for(int i=ls;i>=1;--i)  ny[i-1]=(ny[i]*i)%mod;
36     for(int i=1;i<=n;++i)
37     {
38         int l,r;  scanf("%lld%lld",&l,&r);
39         zuo[l]++;  you[r]++;
40     }
41     if(2*n>m)  {printf("0
");  return 0;}
42     for(int i=1;i<=m;++i)  {zuo[i]+=zuo[i-1];  you[i]+=you[i-1];}
43     f[0][0]=1;
44     for(int i=1;i<=m;++i)
45     {
46         for(int j=0;j<=min(i,n);++j)
47         {
48             f[i][j]=(f[i][j]+f[i-1][j])%mod;
49             if(j>0)  f[i][j]=(f[i][j]+f[i-1][j-1]*(you[i]-j+1))%mod;
50             f[i][j]=(f[i][j]*A(i-j-zuo[i-1],zuo[i]-zuo[i-1]))%mod;
51         }
52     }
53     printf("%lld
",f[m][n]);
54     return 0;
55 }
View Code

T3

那个稍长的式子实际上是循环左移(不知道的问度娘吧)?是我见不多识不广了,那么对于异或来说,移位的影响其实很好解决,毕竟你不管是先移位再$xor$还是先$xor$再移位都可以得到正确答案,那对于中途$xor$一部分之后移位再继续$xor$,完全可以提前处理出来已知$a$数组的不同异或和,这样的话我们就可以得到$m-1$个不同的异或和,你的任务是选一个和$[0,2^n)$之间的数异或值最大,那我们完全可以把这些01串放到$trie$树上去跑,当然题目中那句对手会让结果尽量小也很重要,他提醒我们要计算最小值的最大值,对于某一位来说如果$trie$树上既有0又有1,那这一位一定无法作出贡献,如果两者只有其一,那一定会作出贡献,所以建出$trie$树之后,$dfs$跑一下就可以了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define int long long
 5 #define maxm 100100
 6 #define maxx 32
 7 using namespace std;
 8 int n,m,tot,Ans,j;
 9 int a[maxm],deep[maxx*maxm];
10 int trie[maxm*maxx][3];
11 void jian(int x)
12 {
13     int p=0;
14     for(int k=n-1;k>=0;--k)
15     {
16         int ch=(x>>k)&1;
17         if(trie[p][ch]==0)  {trie[p][ch]=++tot;  deep[trie[p][ch]]=k;}
18         p=trie[p][ch];
19     }
20 }
21 void dfs(int x,int w)
22 {
23     if(trie[x][0]&&trie[x][1])  {dfs(trie[x][0],w);  dfs(trie[x][1],w);}
24     else if(!trie[x][0]&&trie[x][1])  dfs(trie[x][1],w+(1<<deep[trie[x][1]]));
25     else if(trie[x][0]&&!trie[x][1])  dfs(trie[x][0],w+(1<<deep[trie[x][0]]));
26     else if(!trie[x][0]&&!trie[x][1])
27     {
28         if(w==Ans)  j++;
29         else if(w>Ans)  {Ans=w;  j=1;}
30         return ;
31     }
32 }
33 signed main()
34 {
35     scanf("%lld%lld",&n,&m);
36     for(int i=1;i<=m;++i)  {int x;  scanf("%lld",&x);  a[i]=a[i-1]^x;}
37     for(int i=0;i<=m;++i)
38     {
39         int ls=1<<n;
40         int ans=((2*a[i])/ls+2*a[i])%ls;
41         ans=ans^a[m]^a[i];  jian(ans);
42     }
43     dfs(0,0);
44     cout<<Ans<<endl<<j<<endl;
45     return 0;
46 }
View Code
原文地址:https://www.cnblogs.com/hzjuruo/p/11291076.html