CSP2020 游记,总结与题解

游记

考前一周

就完全学不太进去文化课了

然后特别想停课但是不行

结果每天翘着作业苟机房,被老师在后面喊打文化课笔记没整呀这样子

Day 0

早上学了一节物理和语文课

(结果考试语文年级 (5001) 名)

接着拿上了东西就出发了

在去德州的大巴上一直和 (An\_Fly) 聊天

到车站面到了 (hzoi2019) 和换了发型的 (skyh)

晚上打了牛客,(orz happyguy) (1A) 下凸包

Day 1

上午学了四毛子算法,颓过了 (Loj6499)

剩下总结下考试吧


关于 (T1)

这次做的比较好的就是没有怵那个大模拟,然后先写了个暴力代码然后算出来了到换历的那些天这样子

这里以后也可以先写个可以帮着算辅助数据和对拍的暴力

其实本质上还是这次暴力写得比较快比较对,也得益于平常训练里面代码能力的提升吧

不过问题就是以后要先考虑测一下大样例再去拍,万一大样例忘记测结果一测挂掉没时间改了那就不成了

关于 (T2)

还是要积累经验和思路吧,二分那个 (Q_i) 没有用是一个,同时还有直接与到一起那样子做

最后的最后: (ull\_ range:[0,2^{64}-1])

如果是减掉一些数的话可以之直接这样写:

(~0ull)-(n-1)

以后考试的时候在简单题目上面不能花费太长时间了,这一下子干掉 (2.5h) 是真的受不了,还得慢慢提升这方面的速度

关于 (T4)

其实考场想到了维护一个最小值,但是不论是写多少分的暴力都没想到可以先记录然后逆序扫,这个确实成了我得到可观分数的一个障碍,这题目收获在这点上了

还有一个就是可以简单写个 (set) 的问题不要写 (splay) ,花时间长,这题目上是一个,还有那个集合论

原来确实没有见过单调队列维护一些信息的,通过贪吃蛇和蚯蚓俩题也积累了一个思路

关于 (T3)

因为是只有 (10min) 写的,没写挂就谢天谢地了

如果再给时间想可能能想到吧,赛时有些细节可能会想不太清楚

大体来看,这次暴力没有打满,就还有不小的提升空间,那么以后就多练练短时间内快速拿高暴力分的能力吧,后俩题的正解就行稳致远了

Solution

儒略日

模拟即可,注意天数太大的要四百年维护一下

写了 (2.5h) 真不知道这题解应该咋写

动物园

直接枚举哪些位已经被占了,这里直接把所有的数字与到一起就行了

注意处理爆 (ull) 的情况

函数调用

发现这个调用肯定是个 (DAG)

按照一些做法就是加法直接跟着后面的乘法做

那么先统计所有序列里面的乘法量,然后拓扑标记和方案

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
namespace yspm{
	inline int read(){
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int mod=998244353,N=1e5+10;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int del(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return x*y-x*y/mod*mod;}
	vector<int> g[N];
	queue<int> q;
	int n,m,a[N],tag[N],v[N],pos[N],num[N],opt[N],in[N],Q,c[N],b[N];
	inline void dfs(int x){
		if(~tag[x]) return ;
		if(opt[x]==1) return tag[x]=1,void();
		if(opt[x]==2) return tag[x]=v[x],void();
		int siz=g[x].size(); tag[x]=1;
		for(reg int i=0;i<siz;++i){
			int t=g[x][i]; dfs(t); 
			tag[x]=mul(tag[x],tag[t]);
		}return ;
	}
	signed main(){
		freopen("call.in","r",stdin);
		freopen("call.out","w",stdout);
		n=read(); for(reg int i=1;i<=n;++i) a[i]=read();
		m=read(); 
		for(reg int i=1;i<=m;++i){
			opt[i]=read(); 
			if(opt[i]==1) pos[i]=read(),v[i]=read();
			if(opt[i]==2) v[i]=read();
			if(opt[i]==3){
				int x,siz=read(); 
				while(siz--) x=read(),in[x]++,g[i].push_back(x);
			}
		} 
		memset(tag,-1,sizeof(tag));
		for(reg int i=1;i<=m;++i) dfs(i);
		Q=read();
		for(reg int i=1;i<=Q;++i) num[i]=read();
		int now=1;
		for(reg int i=Q;i>=1;--i){
			if(opt[num[i]]==1){
				b[num[i]]=add(b[num[i]],now);
			}else if(opt[num[i]]==2){
				now=mul(now,tag[num[i]]);
			}else if(opt[num[i]]==3){
				b[num[i]]=add(b[num[i]],now);
				now=mul(tag[num[i]],now);
			}
		}
		for(reg int i=1;i<=n;++i) a[i]=mul(a[i],now);
		for(reg int i=1;i<=m;++i) if(!in[i]) q.push(i);
		while(!q.empty()){
			int fr=q.front(); q.pop();
			if(opt[fr]==2) continue;
			if(opt[fr]==1){
				a[pos[fr]]=add(a[pos[fr]],mul(v[fr],b[fr]));
				continue;
			}
			int tmp=1,siz=g[fr].size();
			for(reg int i=siz-1;i>=0;--i){
				int t=g[fr][i]; 
				b[t]=add(b[t],mul(tmp,b[fr]));
				tmp=mul(tmp,tag[t]);
				--in[t]; if(!in[t]) q.push(t);
			}
		}
		for(reg int i=1;i<=n;++i) printf("%lld ",a[i]); puts("");
		return 0;
	}
}
signed main(){return yspm::main();}

考后补的

贪吃蛇

考试的是推递归关系没有推清楚

然后 (sb) 一样的 (70 o 20)

现在写篇博客记录一下暴力做法

我们发现这里的最大最小值用 (set) 维护一下

然后把所有的蛇吃的情况模拟出来之后逆序扫一下,如果发现不满足的之际把后面的都置空

那么这样的做法是 (O(Tnlog n))

然后发现后面的扫是不能降复杂度或者得到更好的做法

那么优化前面求最大最小值的部分


以下参考了 (EI) 博客

考虑最大值和最小值的改变

如果 (a_nge 2 a_1) 那么最小值肯定是 (min(a_2,a_n-a_1))

这时候就按照 (NOIP2016) 蚯蚓的套路来进行维护俩单调队列即可

单调性请自行证明

如果 (a_nle 2 a_1) 那么就先将已经维护的两个队列归并一下,这部分可以做到 (O(n))

因为减掉之后(a_n-a_1<a_2) 那么直接成为最小值就行了

不难证明剩下吃的都是小于 (a_2) 的量

如果最后剩下很多值都是(a_1) 但是 (id) 不同,模拟情况即可

因为大模拟写得不少了,就不展开写了

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define reg register
namespace yspm{
    inline int read(){
        int res=0,f=1; char k;
        while(!isdigit(k=getchar())) if(k=='-') f=-1;
        while(isdigit(k)) res=res*10+k-'0',k=getchar();
        return res*f;
    }
    const int N=1e6+10;
    struct node{
        int v,id;
        bool operator<(const node &a)const{
            if(v^a.v) return v<a.v;
            return id<a.id;
        }
        bool operator ==(const node &a)const{return v==a.v&&id==a.id;}
    }p[N],q1[N],q2[N],q3[N];
    bool fl[N],vis[N];
    int pre[N],n,s1[N],s2[N],cnt,a[N],t1,t2,t3,h1,h2,h3;
    inline int size2(){return t2-h2+1;}
    inline int size1(){return t1-h1+1;}
    inline void EI_method(){
        memset(vis,0,sizeof(vis));
        int mnv=q3[h3].v; vis[q3[h3].id]=1;
        int id=1,fp=1;  while(fp<=t3&&q3[fp].v==mnv) vis[q3[fp].id]=1,++fp;
        while(!vis[id]) ++id; node tmp=(node){-1,-1};
        for(reg int i=t3;i>=fp;--i){
            s2[++cnt]=q3[i].id;
            if(tmp.id!=-1){
                s1[cnt]=tmp.id;
                if((node){q3[i].v-tmp.v,q3[i].id}<(node){mnv,id}) tmp=(node){q3[i].v-tmp.v,q3[i].id};
                else vis[q3[i].id]=1,tmp.id=-1,tmp.v=-1;
            }else{
                s1[cnt]=id; vis[id]=0; 
                while(id<=n&&!vis[id]) ++id; 
                tmp=(node){q3[i].v-mnv,q3[i].id};
            } 
        }
        if(tmp.id!=-1&&tmp.v==mnv){
            id=tmp.id; tmp.id=-1; tmp.v=-1; 
            vis[id]=1;    
        }
        if(tmp.id!=-1){
            for(reg int i=n;i>=1;--i){
                if(vis[i]) s1[++cnt]=tmp.id,s2[cnt]=i,tmp.id=i;
            }
        }else{
            for(reg int i=n,cur=0;i>=1;--i){
                if(!vis[i]) continue; cur^=1;
                if(cur){
                    if(tmp.id!=-1) s1[++cnt]=tmp.id,s2[cnt]=i; 
                    tmp.id=i; 
                }else s1[++cnt]=i,s2[cnt]=tmp.id; 
            }
        }return ;
    }
    inline void work(){
        h1=1; t2=n; h2=n+1; t1=0; cnt=0;
        memset(fl,0,sizeof(fl));
        for(reg int i=1;i<=n;++i) q1[++t1]=p[i]=(node){a[i],i};
        for(reg int i=1;i<=n;++i){
            node mx=(node){-1,-1},mn=(node){9e18+10,9e18+10};
            if(size1()) mx=max(mx,q1[t1]),mn=min(mn,q1[h1]);
            if(size2()) mx=max(mx,q2[t2]),mn=min(mn,q2[h2]);
            if(mx.v<mn.v*2){
                h3=1; t3=0; 
                while(size1()&&size2()){
                    if(q1[h1]<q2[h2]) q3[++t3]=q1[h1++];
                    else q3[++t3]=q2[h2++];
                } 
                while(size1()) q3[++t3]=q1[h1++];
                while(size2()) q3[++t3]=q2[h2++];
                EI_method();
                break;
            }else{
                s1[++cnt]=mn.id; s2[cnt]=mx.id;
                if(size2()&&mx==q2[t2]) t2--; else t1--;
                if(size2()&&mn==q2[h2]) h2++; else h1++;
                q2[--h2]=(node){mx.v-mn.v,mx.id};
            } 
        }
        int las=n; 
        for(reg int i=1;i<=n-1;++i) fl[s1[i]]=1;
		for(reg int i=n-1;i>=1;--i){
			if(fl[s2[i]]){
				while(las>i) fl[s1[--las]]=0;
			} 
		}printf("%lld
",n-las+1); 
		return ;
    }
    signed main(){
        freopen("snakes.in","r",stdin);
        freopen("snakes.out","w",stdout);
        int T=read(); T--;
        n=read(); for(reg int i=1;i<=n;++i) a[i]=read(); work();
        while(T--){
            int pos,v,siz=read();
            while(siz--) pos=read(),v=read(),a[pos]=v;
            work();
        }
        fclose(stdin); fclose(stdout);
        return 0;
    }
}
signed main(){return yspm::main();}
原文地址:https://www.cnblogs.com/yspm/p/13966385.html