[NOIP模拟16]题解

A.Blue

出题人大概已经去为国家处理积压子弹了?

贪心,让每一只青蛙(我怂行吧)都尽量往远跳,能到达的最远的被踩了就跳次远的,以此类推。可以维护一个单调队列,表示每只青蛙的位置(开始都是0)。然后按顺序扫一遍每个石头,如果队首的青蛙不能跳过去就放弃它直接pop掉,如果能跳就把石头位置从队尾push进去并pop掉队首的旧位置,最后队列的size就是答案。因为你肯定不能可着一个青蛙往前跳,必须尽量不让任何一只掉队,所以一只跳完之后把它丢到队尾。

比较神奇的是这道题用STL会比手写队列快300ms??

#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e6+5;
int T,n,m,D,L;
int a[N];
void work()
{
    cin>>n>>m>>D>>L;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    a[n+1]=L;
    deque<int> q;
    for(int i=1;i<=m;i++)q.push_back(0);
    for(int i=1;i<=n+1;i++)
    {
        while(!q.empty()&&q.front()+D<a[i])q.pop_front();
        q.push_back(a[i]);q.pop_front();
    }
    if(q.size()==m)puts("Excited");
    else printf("%d
",q.size());
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>T;
    while(T--)work();
    return 0;
}
STL:deque
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e6+5;
int T,n,m,D,L;
int a[N],q[N];
void work()
{
    cin>>n>>m>>D>>L;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    a[n+1]=L;
    memset(q,0,sizeof(q));
    int head=1,tail=m;
    for(int i=1;i<=n+1;i++)
    {
        while(head<=tail&&q[head]+D<a[i])head++;
        q[++tail]=a[i];head++;
    }
    if(tail-head+1==m)puts("Excited");
    else printf("%d
",tail-head+1);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>T;
    while(T--)work();
    return 0;
}
数组

B.Weed

好题,先咕着

用线段树维护操作的题还是第一次见

线段树上的区间指的是一段连续的操作区间,而不是实际的序列

维护$add$(加了多少层)$del$(删了多少层)$sum$(有多少量)$lsum(被兄弟删除后的量,仅对左儿子维护)$

$up()$的时候如果左儿子不够右儿子删,直接清0即可。但要是右儿子删不完左儿子就很麻烦了。需要专门设计一个函数计算当前区间中删了x个元素的和。

(于是我又懒癌发作了)

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0',ch=getchar();}
    return x*f;
}
const int N=2e5+55;
#define ls(k) k<<1
#define rs(k) k<<1|1
int m,Q;
struct ques
{
    int op,val;
}q[N];
int del[N<<2],add[N<<2],lsum[N<<2],sum[N<<2];
int query(int k,int val)
{
    if(val==add[rs(k)])return lsum[ls(k)];
    if(val>add[rs(k)])return query(ls(k),val-add[rs(k)]+del[rs(k)]);
    if(val<add[rs(k)])return lsum[ls(k)]+query(rs(k),val);
}
void up(int k)
{
    if(add[ls(k)]<=del[rs(k)])
    {
        lsum[ls(k)]=0;
        sum[k]=sum[rs(k)];
        add[k]=add[rs(k)];
        del[k]=del[rs(k)]+del[ls(k)]-add[ls(k)];
    }
    else
    {
        del[k]=del[ls(k)];
        add[k]=add[ls(k)]+add[rs(k)]-del[rs(k)];
        if(del[rs(k)])lsum[ls(k)]=query(ls(k),del[rs(k)]);
        else lsum[ls(k)]=sum[ls(k)];
        sum[k]=sum[rs(k)]+lsum[ls(k)];
    }
}
void build(int k,int l,int r)
{
    if(l==r)
    {
        if(q[l].op==0)add[k]=1,sum[k]=lsum[k]=q[l].val;
        else del[k]=q[l].val;
        return ;
    }
    int mid=l+r>>1;
    build(ls(k),l,mid);build(rs(k),mid+1,r);
    up(k);
}
void update(int k,int l,int r,int pos,int op,int val)
{
    if(l==r)
    {
        lsum[k]=add[k]=sum[k]=del[k]=0;
        if(op)
            del[k]=val;
        else
            add[k]=1,sum[k]=lsum[k]=val;
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid)update(ls(k),l,mid,pos,op,val);
    else update(rs(k),mid+1,r,pos,op,val);
    up(k);
}
int main()
{
    /*freopen("weed.in","r",stdin);
    freopen("my.out","w",stdout);*/
    m=read();Q=read();
    for(int i=1;i<=m;i++)
        q[i].op=read(),q[i].val=read();
    build(1,1,m);
    for(int i=1;i<=Q;i++)
    {
        int num=read(),op=read(),val=read();
        update(1,1,m,num,op,val);
        printf("%d
",sum[1]);
    }
    return 0;
}
View Code

C.Drink

没有打恶心至极的大常数正解,其实优化暴力+卡常跑出来和正解的时间相差无几。

%%%WHS式循环展开 TQL 帅过WYS

 优化暴力的思路就是每层矩形只枚举最上面的那条边上的点,因为有了这条边上一个点的坐标就可以完成矩形上四个点的旋转,所以只枚举一条边上的点就能完成整个矩形的旋转。

然后调整边长和左上角坐标,对每层矩形都来一遍就好了。复杂度其实相比最暴力的没有变,但是循环次数少了,相当于一种循环展开。

当然还要稍作卡常,$int$转$char$  $getchar$读入  $putchar$输出啥的

#include<cstdio>
#include<iostream>
#include<cstring>
#define re register
using namespace std;
const int N=3005;
int n,m,Q,x,y,c;
char a[N][N],b[N][N];
inline int read()
{
    re int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int main()
{
    n=read();m=read();Q=read();
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
        {
            a[i][j]=getchar();
            while(!isdigit(a[i][j]))a[i][j]=getchar();
        }
    while(Q--)
    {
        x=read();y=read();c=read();
        for( ;c>1;c-=2,x++,y++)
        {
            re int L=y,U=x,D=x+c-1,R=y+c-1;
            for(re int i=0;i<=c-2;i++)
            {
                char old=a[U+i][R];
                a[U+i][R]=a[U][L+i];
                a[U][L+i]=a[D-i][L];
                a[D-i][L]=a[D][R-i];
                a[D][R-i]=old;
            }
        }
    }
    for(re int i=1;i<=n;i++)
    {
        for(re int j=1;j<=m;j++)
            putchar(a[i][j]),putchar(' ');
        putchar('
');
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Rorschach-XR/p/11333782.html