Loading

Noip模拟5 2021.6.7

T1 string(线段树优化)

看到数据范围就必须要想到优化,那么如何把26×MN 的复杂度降低呢??

用到那个我们最不想打的数据结构——线段树。。。。。。

然而,这个线段树与往常不同,他只需要用lazy下标,这样的话,也会比往常的码量稍微小点

(听别人说,这提可能还需要卡常)

不说了,代码表示比较明白

 
 1 #include<bits/stdc++.h>
 2 #define lid (id<<1)
 3 #define rid (id<<1|1)
 4 using namespace std;
 5 inline int read(){
 6     int x=0,f=1; char ch=getchar();
 7     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 8     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 9     return x*f;
10 }
11 int n,m,summ[27];char s[100005];
12 struct tree{
13     int l,r,sum,lazy;
14 }; tree t[100005<<2];
15 inline void pushup(int id){
16     if(t[lid].sum==t[rid].sum) t[id].sum=t[lid].sum;
17     else t[id].sum=-1;
18 }
19 
20 inline void pushdown(int id){
21     if(t[id].sum!=-1) t[lid].sum=t[rid].sum=t[id].sum;
22 }
23 
24 inline void bt(int id,int l,int r){
25     t[id].l=l;  t[id].r=r; t[id].sum=-1;
26     if(l==r){ t[id].sum=s[l]-'a'; return; }
27     int mid=(l+r)>>1;
28     bt(lid,l,mid);
29     bt(rid,mid+1,r);
30     pushup(id);
31 }
32 
33 inline void add(int id,int l,int r){
34     if(t[id].l>=l&&t[id].r<=r){
35         if(t[id].sum!=-1){
36             summ[t[id].sum]+=t[id].r-t[id].l+1;
37             return;
38         }
39     }
40     pushdown(id);
41     int mid=(t[id].l+t[id].r)>>1;
42     if(l<=mid) add(lid,l,r);
43     if(mid+1<=r) add(rid,l,r);
44 }
45 
46 inline void change(int id,int l,int r,int v){
47     if(l>r) return;
48     if(t[id].l>=l&&t[id].r<=r){ t[id].sum=v; return;}
49     int mid=(t[id].l+t[id].r)>>1;
50     if(l<=mid) change(lid,l,r,v);
51     if(mid+1<=r) change(rid,l,r,v);
52     pushup(id);
53 }
54 
55 inline void qu(int id){
56     if(t[id].sum!=-1){
57         for(int i=1;i<=t[id].r-t[id].l+1;i++)
58             putchar(t[id].sum+'a');
59         return;
60     }
61     qu(lid);
62     qu(rid);
63 }
64 namespace WSN{
65     inline int main(){
66         n=read(),m=read();
67         scanf("%s",s+1);
68         bt(1,1,n);
69         while(m--){
70             memset(summ,0,sizeof(summ));
71             int l=read(),r=read(),x=read();
72             add(1,l,r);
73             if(x==1){
74                 int ll=l;
75                 for(int i=0;i<=25;i++){
76                     change(1,ll,ll+summ[i]-1,i);
77                     ll+=summ[i];
78                 }
79             }
80             if(x==0){
81                 int ll=l;
82                 for(int i=25;i>=0;i--){
83                     change(1,ll,ll+summ[i]-1,i);
84                     ll+=summ[i];
85                 }
86             }
87         }
88         qu(1);
89         return 0;
90     }
91 }
92 signed main(){return WSN::main();}
View Code

T2 Matrix(Dp)

首先说一下,当这个题我看到dp方程表示的含义时,就吐了。。。这什么鬼才想出来的??? %%cbx

dp[i][j]表示在扫描到第i列时右区间的左端点在第i列左侧的个数是j,数组反映方案数。

唉,这大长定语我身为语文弱者已经尽力了。。。

数组l,r分别表示左区间的右端点在1~l间的个数:右区间的左端点在1~r间的个数,相当于维护一个前缀和

先考虑左区间:

扫描过一列后,扫面下一列而l[i]==l[i-1],表示该列无新的扫描完的左区间: f[i][j]=f[i1-][j]

扫描过一列后,扫面下一列而l[i]!=l[i-1],表示该列有新的扫描完的左区间:

 总共有 l[i]−l[i−1]个左区间需要安排 1 ,之前还空着的列有 i−j−l[i−1] 个,所以安排左区间的方案数为

    $P^{l[i]-l[i-1]}_{i-j-l[i-1]}$

再考虑右区间:

j>0,则f[i][j]可以由f[i-1][j-1]转移而来。总共r[i]行,放了j-1行,还剩r[i]-(j-1)行:

    $f [ i ][ j ]+=f [ i - 1 ][ j-1 ]*[r[i]-(j-1)]*P^{l[i]-l[i-1]}_{i-j-l[i-1]}$

 1 #include<bits/stdc++.h>
 2 #define int long long 
 3 using namespace std;
 4 inline int read(){
 5     int x=0,f=1; char ch=getchar();
 6     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 7     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 8     return x*f;
 9 }
10 const int NN=3002,p=998244353;
11 int n,m,l[NN],r[NN],f[NN][NN];
12 namespace WSN{
13     inline int main(){
14         f[0][0]=1;
15         n=read(),m=read();
16         for(int i=1;i<=n;i++){ 
17             int L=read(),R=read(); 
18             l[L]++,r[R]++;
19         }
20         for(int i=1;i<=m;i++){
21             f[i][0]=f[i-1][0]; 
22             l[i]+=l[i-1]; 
23             r[i]+=r[i-1];
24             for(int j=1;j<=i;j++)
25                 f[i][j]=(f[i-1][j]+f[i-1][j-1]*(r[i]-(j-1))%p)%p;
26             for(int k=0;k<=i;k++)
27                 for(int j=l[i-1];j<l[i];j++)
28                     f[i][k]=f[i][k]*(i-j-k)%p;
29         }
30         printf("%lld\n",f[m][n]);
31         return 0;
32     }
33 }
34 signed main(){return WSN::main();}
View Code

T3 Big (trie树)

巧妙的将复杂的函数取模柿子转化为理解的懂得柿子:

前面的地板函数模完2^n后值域是0和1,后面加上2x并模一个2^n意思是向左移一位加起来就是相当于将原数的二进制首位推到末尾,其他位向前移动一位,举个不是二进制的例子

1234----->> 2341

这样,我们就可以明显的发现这是一道trie树题

我们以对手的操作为断点,前面会让x xor一些数,操作后也会xor,这样,我们可以记录前缀和,枚举对手操作的各种断点,这样就可以找到最优解了

再提一下的就是分情况

一节点有两个孩子,那么无论我们如何构造x,对手一定能将这一位变为0,所以答案这一位为0

 如果只有一个儿子,那么我们一定可以构造出一个x,使答案的这一位为1,所以答案这一位为1。

所以一边记录最大值一边统计个数就完了

 1 #include<bits/stdc++.h>
 2 #define X ((x>>(i-1))&1)
 3 using namespace std;
 4 inline int read(){
 5     int x=0,f=1; char ch=getchar();
 6     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 7     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
 8     return x*f;
 9 }
10 const int NN=300005;
11 int n,m,ch[8000000][3],tot=1,a[NN],s[NN],ans1,ans2;
12 inline int change(int x){return (x>>(n-1))+((x&(~(1<<(n-1))))<<1);}
13 //attacker use problem idea to change the number 
14 inline void insert(int x){
15     int u=1;
16     for(int i=n;i>=1;i--){
17         if(!ch[u][X]) ch[u][X]=++tot;
18         u=ch[u][X];
19     }
20 }
21 inline void dfs(int u,int x,int len){
22     if(len==0){
23         if(x>ans1){
24             ans1=x;
25             ans2=1;
26         }else if(x==ans1) ans2++;
27         return;
28     }
29     if(ch[u][0]&&ch[u][1]){
30         dfs(ch[u][0],x,len-1);
31         dfs(ch[u][1],x,len-1);
32     }
33     if(ch[u][0]&&!ch[u][1]) dfs(ch[u][0],(x|(1<<(len-1))),len-1);
34     if(ch[u][1]&&!ch[u][0]) dfs(ch[u][1],(x|(1<<(len-1))),len-1);
35 }
36 namespace WSN{
37     inline int main(){
38         n=read(),m=read();//n mean the length of "2 jinzhi"
39         for(int i=1;i<=m;i++) a[i]=read();
40         for(int i=1;i<=m;i++) s[i]=s[i-1]^a[i];//xor "qian z s[m]^s[i]));
41         for(int i=0;i<=m;i++) insert(change(s[i])^(s[m]^s[i]));
42         dfs(1,0,n);
43         printf("%d\n%d\n",ans1,ans2);
44         return 0;
45     }
46 }
47 signed main(){return WSN::main();}
View Code

END

这次考试还是有小问题,就是时间分配不均。

超级有自信的打过了T4,然而也花费了超级多的时间,结果是T4没有拿到满分,前面题也顾不上做,幸好前面的题整体得分不高,而我的第四题想的也是正解思路,总之不亏吧~~

再%%XIN考试全场首A第四题太强了

posted @ 2021-06-16 19:11  雪域亡魂  阅读(82)  评论(0)    收藏  举报