模拟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 }
View Code

 

 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 }
View Code

 

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 }
View Code

 

posted @ 2019-08-11 21:34  casun547  阅读(158)  评论(0编辑  收藏  举报