模拟16 题解
T1[A. Blue]
贪心,对于每只青蛙,跳的时候尽量远,越远选择越多
注意若用set实现,要先insert(0)
1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 #include<cstring>
5 #include<algorithm>
6 #include<set>
7 #define R register
8 using namespace std;
9 inline int read()
10 {
11 int x=0;char ch=getchar();
12 while(ch>'9'||ch<'0')ch=getchar();
13 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
14 return x;
15 }
16 const int maxn=1000005;
17 int n,m,d,l;
18 set<int>s;
19 int main()
20 {
21 //freopen("blue4.in","r",stdin);
22 int T=read();
23 while(T--)
24 {
25 s.clear();s.insert(0);//it: set:3 4 5 ,upper_bound(6)->s.end();->cout<<*it的结果是s.size()
26 // it: set:5 upper_bound(4)->s.begin(),,若--it还会是begin(),而此时pos==0,x>=pos+d,却会跳过去
27 //总之set最好先insert(0);
28 n=read(),m=read(),d=read(),l=read();
29 for(R int i=1;i<=n;++i)
30 {
31 int x=read();
32 s.insert(x);
33 }
34 if(d==l){puts("Excited");continue;}
35 int pos=0,ans=0;
36 while(s.size())
37 {
38 if(ans>=m)break;
39 if(pos+d>=l)
40 {
41 pos=0;ans++;
42 continue;
43 }
44 set<int>::iterator it=s.upper_bound(pos+d);
45 int x=*--it;
46 if(x<=pos)break;
47 s.erase(x);
48 pos=x;
49 }
50 if(pos+d>=l)ans++;
51 if(ans>=m)puts("Excited");
52 else printf("%d\n",ans);
53 }
54 }
T2[B. Weed]
线段树:以时间为下标,建一颗线段树,维护以下信息:
1.s,这个区间的ans值,就是量2.na,这个区间的当前层数,3.nd这个区间还没有删完的层数
那某个区间怎么会na与nd同时存在? 是因为这个区间中,删除操作在左面,而增加在右面,删除操作无法影响后面的,
怎么维护:读入初始数据,建树和修改时,将子节点信息update到父节点是关键,
分三种情况讨论,见代码注释
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #define R register
5 #define lc (k<<1)
6 #define rc (k<<1|1)
7 #define mid ((t[k].l+t[k].r)>>1)
8 using namespace std;
9
10 inline int read()
11 {
12 int x=0;char ch=getchar();
13 while(ch>'9'||ch<'0')ch=getchar();
14 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
15 return x;
16 }
17 const int maxn=2e5+5;
18 int m,q;
19 int b[maxn],v[maxn];
20 struct node{
21 int k,l,r,s,na,nd;
22 }t[4*maxn];
23 int cal(int k,int res)//k子树减去res后的s值
24 {
25 if(t[rc].na==res)return t[k].s-t[rc].s;//右儿子正好被减完,不能写成t[lc].s,这代表只考虑左儿子自己的s值,左右合并后就变了,
26 if(t[rc].na>res)return t[k].s-t[rc].s+cal(rc,res);//右儿子比较多,还要加上cal
27 if(t[rc].na<res)return cal(lc,res-t[rc].na+t[rc].nd);//右儿子太少了,减没了,所以不用加右儿子的s,但是t[rc].nd还要给前面减掉
28 }
29 void update(int k)
30 {
31 if(t[lc].na<=t[rc].nd)//左儿子不够减
32 {
33 t[k].nd=t[rc].nd+t[lc].nd-t[lc].na;//总的nd还要加上左儿子剩的
34 t[k].s=t[rc].s;t[k].na=t[rc].na;//左儿子减没了
35 }
36 else if(t[rc].nd==0)//rc没减的
37 {
38 t[k].s=t[lc].s+t[rc].s;
39 t[k].na=t[lc].na+t[rc].na;
40 t[k].nd=t[lc].nd;
41 }
42 else//左儿子没被减完
43 {
44 t[k].nd=t[lc].nd;
45 t[k].na=t[lc].na+t[rc].na-t[rc].nd;
46 t[k].s=t[rc].s+cal(lc,t[rc].nd);//cal来计算左儿子被减之后的s
47 }
48 }
49 void build(int k,int l,int r)
50 {
51 t[k].l=l,t[k].r=r;
52 if(l==r)
53 {
54 int kk=t[k].l;
55 if(b[kk]) t[k].nd=v[kk];
56 else t[k].na=1,t[k].s=v[kk];
57 return;
58 }
59 build(lc,l,mid);
60 build(rc,mid+1,r);
61 update(k);
62 }
63 void change(int k,int l,int r,int pos,int bl,int vl)
64 {
65 if(t[k].l==t[k].r)
66 {
67 if(bl) t[k].nd=vl,t[k].na=t[k].s=0;
68 else t[k].na=1,t[k].s=vl,t[k].nd=0;
69 return;
70 }
71 if(pos<=mid)change(lc,l,mid,pos,bl,vl);
72 else change(rc,mid+1,rc,pos,bl,vl);
73 update(k);
74 }
75 int main()
76 {
77 // freopen("weed.in","r",stdin);
78 m=read(),q=read();
79 for(int i=1;i<=m;i++)
80 b[i]=read(),v[i]=read();
81 build(1,1,m);
82 for(int i=1;i<=q;i++)
83 {
84 int k=read(),bl=read(),vl=read();
85 change(1,1,m,k,bl,vl);
86 printf("%d\n",t[1].s);
87 }
88 }
T3[C. Drink]
暴力可以水过,本渣渣就不写正解了,这个坑以后再填
比较好打的暴力:从左上角开始向右枚举每个点放入队列中,然后从右上角开始,向下然后向左枚举,依次从队列中填入,$O(q*2*nm)$
优化常数2:对于每一次翻转,四个点同时转,这样常数变为$1/4$
1 #include<iostream>
2 #include<cstdio>
3 #include<cmath>
4 #define R register
5 using namespace std;
6 char a[2005][2005],q[4000001];
7 inline int read()
8 {
9 int x=0;char ch=getchar();
10 while(ch>'9'||ch<'0')ch=getchar();
11 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
12 return x;
13 }
14 int main()
15 {
16 //freopen("data","r",stdin);
17 const int n=read(),m=read(),Q=read();
18 for(R int i=1;i<=n;++i)
19 for(R int j=1;j<=m;++j)
20 {
21 R char ch=getchar();
22 while(ch<'0'||ch>'9')ch=getchar();
23 a[i][j]=ch;
24 }
25 for(R int i=1;i<=Q;++i)
26 {
27 const int x=read(),y=read(),len=read();
28 for(R int i=0;i<len/2;++i)
29 {
30 R int x1=x+i,x2=x+i,x3=x+len-1-i,x4=x+len-1-i,y1=y+i,y2=y+len-1-i,y3=y+len-1-i,y4=y+i;
31 while(y1!=y+len-1-i)
32 {
33 R int tt=a[x1][y1];
34 a[x1][y1]=a[x4][y4],a[x4][y4]=a[x3][y3],a[x3][y3]=a[x2][y2],a[x2][y2]=tt;
35 y1++,x2++,y3--,x4--;
36 }
37 }
38 }
39 for(R int i=1;i<=n;++i){
40 for(R int j=1;j<=m;++j)
41 printf("%c ",a[i][j]);
42 puts("");
43 }
44 }
愿你在迷茫时,记起自己的珍贵。