模拟11题解

mac2022-06-30  11

T1[A. string]「桶排序」「线段树」

线段树维护区间的每个字母出现了多少次,

在排序的时候,先查询一个区间的每个字母的出现次数,然后挨个区间赋值

复杂度  $O(mlog(n)*26)$

优化常数(26):定义f(懒标记):f!=0时,代表子树都被赋值为了同一个值;f==0,表示不相等。

将区间查询改为只有访问到了f!=0再对ans贡献return,pushup,pushdown同理,避免了枚举26

当然也可以循环展开勉强卡过

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define mid ((t[k].l+t[k].r)>>1) 6 #define lc (k<<1) 7 #define rc (k<<1|1) 8 #define R register 9 using namespace std; 10 int read() 11 { 12 int f=1,x=0;char ch=getchar(); 13 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 15 return f*x; 16 } 17 const int maxn=100005; 18 struct node{ 19 int l,r,sum,f; 20 }t[maxn*4]; 21 char s[maxn]; 22 int a[maxn],ans[30]; 23 inline void up(R int k) 24 { 25 if(t[lc].f==t[rc].f&&t[lc].f) t[k].f=t[lc].f; 26 else t[k].f=0; 27 } 28 inline void down(R int k) 29 { 30 t[lc].f=t[rc].f=t[k].f; 31 } 32 void build(R int k,R int l,R int r) 33 { 34 t[k].l=l,t[k].r=r; 35 if(l==r) 36 { 37 t[k].f=a[l]; 38 t[k].sum=1; 39 return; 40 } 41 build(lc,l,mid); 42 build(rc,mid+1,r); 43 t[k].sum=t[lc].sum+t[rc].sum; 44 up(k); 45 } 46 void query(R int k,R int l,R int r) 47 { 48 if(t[k].l>=l&&t[k].r<=r&&t[k].f) 49 { 50 ans[t[k].f]+=t[k].sum; 51 return; 52 } 53 if(t[k].f)down(k); 54 if(l<=mid)query(lc,l,r); 55 if(r>mid)query(rc,l,r); 56 up(k); 57 } 58 void change(R int k,R int l,R int r,R int w) 59 { 60 if(t[k].l>=l&&t[k].r<=r) 61 { 62 t[k].f=w; 63 return; 64 } 65 if(t[k].f) down(k); 66 if(l<=mid)change(lc,l,r,w); 67 if(r>mid)change(rc,l,r,w); 68 up(k); 69 } 70 void print(R int k) 71 { 72 if(t[k].l==t[k].r) 73 { 74 char ch=t[k].f+'a'-1; 75 printf("%c",ch); 76 return; 77 } 78 if(t[k].f) down(k); 79 print(lc); 80 print(rc); 81 } 82 int main() 83 { 84 // freopen("data","r",stdin); 85 const int n=read(),m=read(); 86 scanf("%s",s+1); 87 for(R int i=1;i<=n;++i) 88 a[i]=s[i]-'a'+1; 89 build(1,1,n); 90 for(R int i=1;i<=m;++i) 91 { 92 R int l=read(),r=read(),x=read(); 93 memset(ans,0,sizeof ans); 94 query(1,l,r); 95 if(x) 96 { 97 for(R int i=1;i<=26;++i) 98 if(ans[i]) 99 { 100 change(1,l,l+ans[i]-1,i); 101 l=l+ans[i]; 102 } 103 } 104 else 105 { 106 for(R int i=26;i>=1;--i) 107 if(ans[i]) 108 { 109 change(1,l,l+ans[i]-1,i); 110 l=l+ans[i]; 111 } 112 } 113 } 114 print(1); 115 } 116 /* 117 g++ 1.cpp -o 1 118 ./1 119 120 */ View Code

 

T2 [B. matrix]「动态规划--两没一毒」

定义f[i][j]:从左向右到了第i列(也就是有了i个1能放),有j个一放在了右区间,

l[i]:到i列为止,有多少行的左区间已经结束;   r[i]:到i列为止,有多少右区间已经开始;

f[i][j]=f[i-1][j]+f[i-1][j-1]*(r[i]-(j-1));

   前者为不放,后者 是再多放一个,j-1是右区间已经放了j-1个,总共有r[i]个空

f[i][j]要乘上:A(i-j-l[i-1],l[i]-l[i-1])  

  l[i]-l[i-1]是第i列的能放的空,i是总共能有的1的个数,j个放在了右区间,l[i-1]个一定要放在已经结束的i-1个左区间里,剩下的选出来去放在能放的空里

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define int long long 6 using namespace std; 7 const int maxn=3005; 8 const int mod=998244353 ; 9 int read() 10 { 11 int f=1,x=0;char ch=getchar(); 12 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 14 return f*x; 15 } 16 int n,m,l[maxn],r[maxn],f[3005][3005]; 17 signed main() 18 { 19 // freopen("data","r",stdin); 20 n=read(),m=read(); 21 for(int i=1;i<=n;i++) 22 { 23 int li=read(),ri=read(); 24 l[li]++,r[ri]++; 25 } 26 for(int i=1;i<=m;i++) 27 l[i]=l[i-1]+l[i],r[i]=r[i-1]+r[i]; 28 // for(int i=1;i<=m;i++)cout<<l[i]<< 29 f[0][0]=1; 30 for(int i=1;i<=m;i++) 31 { 32 f[i][0]=f[i-1][0]; 33 for(int j=1;j<=r[i];j++) 34 f[i][j]=(f[i-1][j]+f[i-1][j-1]*(r[i]-j+1)%mod)%mod; 35 for(int j=0;j<=min(i,n);j++) 36 for(int k=l[i-1];k<=min(i-j,l[i]-1);k++) 37 f[i][j]=f[i][j]*(i-j-k)%mod; 38 } 39 printf("%lld\n",f[m][n]%mod); 40 } 41 /* 42 g++ 1.cpp -o 1 43 ./1 44 45 */

View Code

T3[C. big]「trie树」

性质:(a^b^c)<<d=(a<<d)^(b<<d)^(c<<d)

性质:对手操作的原式等价与左移,(若2x<2^n相当与左移,反之就是逻辑左移)总之保证操作之后不会超过2^n

所以断点i就是使1~i先都左移再求异或和

处理一个前缀异或和sum,((x^sum[i])<<1)^(sum[m]^sum[i])=(x<<1)^(sum[i]<<1)^(sum[m]^sum[i])

         ((sum[m]^sum[i])是i+1~m的异或和)

其中(x<<1)可以取到2^n中的所有数,对于最终结果没有影响,且不用求它,可忽略

(sum[i]<<1)^(sum[m]^sum[i])将其放入trie树中,从高位向低位存,dfs求最大值,要尽量避开trie树上的点,

trie上只有0或1是对ans的贡献为1,接着沿其递归

但0,1都有时,我选1,对手会选0,我选0,对手会选1,所以对ans的贡献是0,分别搜下去

 

1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #define int long long 6 const int maxn=4000005; 7 using namespace std; 8 int read() 9 { 10 int f=1,x=0;char ch=getchar(); 11 while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} 13 return f*x; 14 } 15 int n,m,p,sum[maxn],a[maxn]; 16 int t[maxn][3],tot; 17 inline int change(int x){return (2*x/p+2*x)%p;} 18 void insert(int x) 19 { 20 int nxt=0; 21 for(int i=n-1;i>=0;i--) 22 { 23 const int fl=(x&(1<<i))?1:0; 24 if(!t[nxt][fl]) t[nxt][fl]=++tot; 25 nxt=t[nxt][fl]; 26 } 27 } 28 int mx,cnt; 29 void dfs(int x,int dep,int ans) 30 { 31 if(dep==-1) 32 { 33 if(ans>mx)mx=ans,cnt=1; 34 else if(ans==mx)cnt++; 35 return; 36 } 37 if(t[x][1]&&t[x][0]) 38 { 39 dfs(t[x][0],dep-1,ans); 40 dfs(t[x][1],dep-1,ans); 41 return; 42 } 43 if(t[x][1]) 44 dfs(t[x][1],dep-1,ans^(1<<dep)); 45 else if(t[x][0]) 46 dfs(t[x][0],dep-1,ans^(1<<dep)); 47 } 48 signed main() 49 { 50 //freopen("data","r",stdin); 51 n=read(),m=read();p=(1<<n); 52 for(int i=1;i<=m;i++){ 53 a[i]=read(); 54 sum[i]=sum[i-1]^a[i]; 55 } 56 for(int i=0;i<=m;i++) 57 insert(change(sum[i])^sum[m]^sum[i]); 58 dfs(0,n-1,0); 59 printf("%lld\n%lld\n",mx,cnt); 60 } 61 /* 62 g++ 3.cpp -o 3 63 ./3 64 65 */ View Code

 

转载于:https://www.cnblogs.com/casun547/p/11289091.html

相关资源:模拟电子线路答案(课后题解)
最新回复(0)