zoukankan      html  css  js  c++  java
  • CSP-S2020题解

    CSP-S2020

    儒略日

    模拟

    分几段来做:

    1. 公元前
    2. 1582年前
    3. 1582年
    4. 1600年及以前
    5. 1600年后

    每次确定到哪四年就可以了,四年之内暴力每一月。

    时间复杂度 (O(48n))

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read(){
    	int x=0,f=1,c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    const int year=365,bc=1721424,bd1=577460;
    int mon[13]={0,31,28,31,30,31,30,31,31,30,31,30,31},ren[5],T;
    inline void chu(int n,int mod,int &x,int &y){
    	x=n/mod;
    	y=n%mod;
    	if(!y){x--;y=mod;}
    }
    inline void getdata(int day,int &n,int &y,int &r){
    	for(int t=1,nw;t<=4;t++){
    		for(int i=1;i<=12;i++){
    			nw=mon[i];
    			if(i==2)nw+=ren[t];
    			if(day>nw)day-=nw;
    			else{
    				n+=t;
    				y=i;
    				r=day;
    				return;
    			}
    		}
    	}
    }
    inline void solve(){
    	static int x,y,u,v,fl,n;
    	memset(ren,0,sizeof(ren));
    	T++;
    	fl=0;
    	n=read()+1;
    	if(n<=bc){
    		chu(n,year*4+1,x,y);
    		ren[1]=1;
    		x*=4;
    		getdata(y,x,u,v);
    		cout<<v<<" "<<u<<" "<<4713-x+1<<" BC
    ";
    		return;
    	}
    	n-=bc;
    	if(n<=bd1){
    		chu(n,year*4+1,x,y);
    		ren[4]=1;
    		x=x*4;
    		getdata(y,x,u,v);
    		cout<<v<<" "<<u<<" "<<x<<"
    ";
    		return;
    	}
    	n-=bd1;
    	if(n<=year-10){
    		mon[10]-=10;
    		x=0;
    		getdata(n,x,u,v);
    		mon[10]+=10;
    		if(u==10&&v>4)v+=10;
    		cout<<v<<" "<<u<<" 1582
    ";
    		return;
    	}
    	n-=year-10;
    	if(n<=year*18+5){
    		chu(n,year*4+1,x,y);
    		ren[2]=1;
    		x=x*4;
    		getdata(y,x,u,v);
    		cout<<v<<" "<<u<<" "<<x+1582<<"
    ";
    		return;
    	}
    	n-=(year*18+5);
    	chu(n,year*400+97,x,y);
    	x=x*400;
    	if(y<=year*100+24);
    	else if(y<=(year*100+24)*2){x+=100;y-=(year*100+24);}
    	else if(y<=(year*100+24)*3){x+=200;y-=(year*100+24)*2;}
    	else{x+=300;y-=(year*100+24)*3;fl=1;}
    	chu(y,year*4+1,u,v);
    	y=v;
    	x+=u*4;
    	if(u<24||fl)ren[4]=1;
    	getdata(y,x,u,v);
    	cout<<v<<" "<<u<<" "<<x+1600<<"
    ";
    }
    signed main(){
    	for(int Q=read();Q--;)solve();
    	return (0-0);
    }
    

    动物园

    位运算 签到题

    已有的位数加上可以不用饲料的位数即为总的可以养的动物数。

    注意特判 n=m=0,k=64 时答案是 (2^{64}) 会爆 long long

    时间复杂度 (O(n+m+k))

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1,c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    #define ul unsigned long long
    inline ul readul(){
    	ul x=0;int c=getchar();
    	while(!isdigit(c))c=getchar();
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return x;
    }
    ul hav;
    int n,m,c,k,zhong,deg[100];
    int main(){
    //	freopen("zoo.in","r",stdin);
    //	freopen("zoo.out","w",stdout);
    	n=read();m=read();c=read();k=read();
    	if(!n&&!m&&k==64){puts("18446744073709551616");return (0-0);}
    	for(int i=1;i<=n;i++)hav|=readul();
    	for(int i=1,x;i<=m;i++){
    		deg[read()]++;
    		x=read();
    	}
    	for(int i=0;i<k;i++)if(!deg[i])hav|=((ul)1<<i);
    	for(int i=0;i<k;i++)if((hav>>i)&1)zhong++;
    	if(zhong<64)hav=((ul)1<<zhong);
    	else hav=0;
    	cout<<hav-n<<"
    ";
    	return (0-0);
    }
    

    函数调用

    拓扑排序 动态规划

    考虑只有乘号直接拓扑排序后 DP,只有加号反拓扑序 DP,每个点经历了几次。

    然后结合的话会有顺序问题,我们先 DP 一次只有乘号,然后反着DP 加号时,要乘上后缀积即可。

    时间复杂度 (O(n+m))

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1,c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    #define ll long long
    const int mod=998244353;
    inline int fix(int x){
    	return x+((x>>31)&mod);
    }
    inline int add(int x,int y){
    	return fix(x+y-mod);
    }
    inline int dec(int x,int y){
    	return fix(x-y);
    }
    inline int mul(int x,int y){
    	return (ll)x*y%mod;
    }
    inline void ADD(int &x,int y){
    	x=fix(x+y-mod);
    }
    inline void DEC(int &x,int y){
    	x=fix(x-y);
    }
    inline void MUL(int &x,int y){
    	x=(ll)x*y%mod;
    }
    const int M=1100004;
    struct edge{
    	int v,nxt;
    }e[M];
    int first[M],deg[M],cnt;
    inline void addedge(int u,int v){
    	e[++cnt].v=v;e[cnt].nxt=first[u];first[u]=cnt;
    	deg[v]++;
    }
    queue<int>q;
    int n,m,Q,a[M],dfn[M],f[M],ml[M],ans[M],op[M],xx[M],vv[M];
    inline void tuopu(){
    	for(int i=m;i;i--)if(!deg[i])q.push(i);
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		dfn[++dfn[0]]=x;
    		for(int i=first[x],v;i;i=e[i].nxt){
    			v=e[i].v;
    			deg[v]--;
    			if(!deg[v])q.push(v);
    		}
    	}
    }
    inline void solve1(){
    	for(int t=m,x;t;t--){
    		x=dfn[t];
    		assert(x);
    		if(op[x]==2){
    			ml[x]=vv[x];
    		}
    		else ml[x]=1;
    		for(int i=first[x],v;i;i=e[i].nxt){
    			v=e[i].v;
    			MUL(ml[x],ml[v]);
    		}
    	}
    }
    inline void solve2(){
    	f[dfn[1]]=1;
    	for(int t=1,x,tmp;t<=m;t++){
    		x=dfn[t];
    		if(op[x]==1){
    			ADD(ans[xx[x]],mul(vv[x],f[x]));
    		}
    		tmp=f[x];
    		for(int i=first[x],v;i;i=e[i].nxt){
    			v=e[i].v;
    			ADD(f[v],tmp);
    			MUL(tmp,ml[v]);
    		}
    	}
    }
    int main(){
    //	freopen("call.in","r",stdin);
    //	freopen("call.out","w",stdout);
    	n=read();
    	for(int i=1;i<=n;i++){
    		a[i]=read();
    	}
    	m=read();
    	for(int i=1,k;i<=m;i++){
    		op[i]=read();
    		if(op[i]==1){
    			xx[i]=read();vv[i]=read();
    		}
    		else if(op[i]==2){
    			vv[i]=read();
    		}
    		else{
    			k=read();
    			for(int j=1;j<=k;j++)addedge(i,read());
    		}
    	}
    	Q=read();
    	++m;
    	for(int i=1;i<=Q;i++)addedge(m,read());
    	tuopu();
    	solve1();
    	solve2();
    	for(int i=1;i<=n;i++)ADD(ans[i],mul(a[i],ml[m]));
    	for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
    	return (0-0);
    }
    

    贪吃蛇

    贪心 博弈 单调性 奇偶性

    先讲讲暴力 (O(nlog n))

    我的暴力:

    求出每个点的 las 最后杀蛇的时刻(时刻从 n1),ded 每只蛇死的的时刻。然后按 las 从小到大排序,若一个蛇的区间内有蛇是肯定不会杀别人的,这只蛇就可以杀,用前缀和维护一下不敢杀的蛇。对所有不敢杀的蛇的 lasmax 即是答案。

    同学的暴力:

    对每个时刻维护一个最近的不敢吃的时刻,上一个时刻要么继承这个时刻要么自己不吃。

    正解 (O(n))

    结论一:若一个时刻 a 吃了 ba 不会变成最小的那么久可以吃。

    下一个时刻 cd,显然有 (c-d<a-b),那么 c 不会被吃 a 就不会被吃。

    结论二:若一个时刻 a 吃了 b 后变成的最小的,那么往下最多只有一轮就结束了。

    若有两轮那么 a 就被吃掉了。

    结论三:每次新产生的会单调递减,但在变成最小后经过一段时间后又不是最小的就会被破坏(值相同时标号会产生这种情况)。

    不是最小时显然是单调的,是最小时下一轮 ca-b(c-a+bleq c) 还是最小的。

    于是先模拟到不是最小的轮数 (res)k 轮后又变成了最小的(用两个队列维护一下),再往下一定最大的就直接吃掉最小的了所以不可能在往下推了。那么 (ans=res-((k&1)xor 1))(k=1) 是显然继续的轮数是 0,(k=2) 时显然是 1,以后可以用类似 SG 函数的推法推出刚才的结论。要特判一下一直到最后都有单调性的情况。

    //starusc
    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1,c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    const int N=1e6+4;
    int n,A[N];
    namespace que{
    	int h1,h2,t1,t2;
    	pair<int,int>q1[N],q2[N];
    	inline void build(){
    		for(int i=1;i<=n;i++)q1[n-i+1]=make_pair(A[i],i);
    		h1=1;t1=n;
    		h2=1;t2=0;
    	}
    	inline pair<int,int> getmx(){
    		if(h2>t2||(h1<=t1&&q1[h1]>q2[h2]))return q1[h1++];
    		return q2[h2++];
    	}
    	inline pair<int,int> getmn(){
    		if(h2>t2||(h1<=t1&&q1[t1]<q2[t2]))return q1[t1--];
    		return q2[t2--];
    	}
    	inline pair<int,int> mnval(){
    		if(h2>t2||(h1<=t1&&q1[t1]<q2[t2]))return q1[t1];
    		return q2[t2];
    	}
    	inline bool dec(){
    		pair<int,int>mx=getmx(),mn=getmn(),nw=make_pair(mx.first-mn.first,mx.second),tmp;
    		if(h1<=t1||h2<=t2)tmp=mnval();
    		q2[++t2]=nw;
    		return (h1>t1&&h2>t2)||nw<tmp;
    	}
    }
    inline void solve(){
    	que::build();
    	int k=1,ans=2;
    	for(int i=n;i>1;i--){
    		if(que::dec()){ans=i;break;}
    	}
    	for(int i=ans-1;i>1;i--){
    		k^=1;
    		if(!que::dec())break;
    	}
    	cout<<ans-k<<"
    "; 
    }
    int main(){
    //	freopen("snakes.in","r",stdin);
    //	freopen("snakes.out","w",stdout);
    	int T=read();
    	for(int tt=1,k,x;tt<=T;tt++){
    		if(tt==1){
    			n=read();
    			for(int i=1;i<=n;i++)A[i]=read();
    		}
    		else{
    			k=read();
    			for(int i=1;i<=k;i++){
    				x=read();
    				A[x]=read();
    			}
    		}
    		solve();
    	}
    	return (0-0);
    }
    

  • 相关阅读:
    Beyond Compare比较图片怎么修改背景颜色
    Leonardo's Notebook UVALive
    Saddle Point ZOJ
    概率dp总结 正在更新
    First Knight UVALive
    Scout YYF I POJ
    RedIsGood TopCoder
    聪聪和可可 HYSBZ
    So you want to be a 2n-aire? UVA
    国家队论文集
  • 原文地址:https://www.cnblogs.com/aurora2004/p/13955903.html
Copyright © 2011-2022 走看看