• 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();}
    
  • 相关阅读:
    约数个数 和 约数之和
    二分模板
    新生赛补题
    codefores刷题心得3 思维+dp(特别好玩)
    二叉树的遍历及例题
    团队作业七——团队作业分配
    WarPlane——游戏设计文档
    团队作业(五)
    团队作业(四)
    团队项目方案分析
  • 原文地址:https://www.cnblogs.com/yspm/p/13966385.html
Copyright © 2020-2023  润新知