[整理]CSP-S2020第二輪試題解析


題面請自行右轉洛谷或任意一個能看到題面的地方。

T1 Julian

Solution:暴力模擬即可,但是需要進行一些運算來減少時間,同時請注意特判。
Code:考場代碼(好長啊)
P.S.這個代碼在洛谷上(官方數據)可以得到100分,但是€€£的菜機測出來好像只有六七十。

T2 Zoo

考場上思路想了一半自己給假了結果最后只打了個40分暴力qaq
Solution:可以先把動物和飼料預處理一下,將讀入的動物或起來,然后再看哪些位需要飼料(\(q_i\)互不相同所以沒用了)。
然后按位考慮什么情況下飼料可以任取:要么是這一位上沒有做出要求(所有動物都不需要這種飼料),要么是這一位已經有了動物。
所以把飼料取反,再和動物或起來,就得到了可以任取的位數。(此處可以參照代碼理解)
但是不幸的是這道題連ull都卡了,需要特判一個\(k=64\)的情況。
Code:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#define us unsigned
#define LL long long
#define rg register
using namespace std;
inline void Read(int &x){
	int f=1;
	x=0;
	char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=(x<<1)+(x<<3)+c-48;
		c=getchar();
	}
	x*=f;
}
#define N 1000010
int n,m,c,k,p,q;
us LL a,animal,food,ans=1;
int main(){
	Read(n),Read(m),Read(c),Read(k);
	for(rg int i=1;i<=n;i++)scanf("%llu",&a),animal|=a;
	for(rg int i=1;i<=m;i++)Read(p),Read(q),food|=1ull<<p;
	animal|=~food;
	for(rg int i=0;i<k;i++){
		ans<<=animal>>i&1;
	}
	if(!ans&&!n)cout<<"18446744073709551616"<<endl;
	else printf("%llu\n",ans-n);
	return 0;
}

T3 Call

Solution:我們考慮操作之間會出現什么影響。
不難發現每個加操作所乘的系數就是它后面的所有乘法操作的后綴積。所以我們可以對每個函數記一個mul表示它所產生的乘法影響(1操作的mul就是1)。
此時一個3操作的mul就是它所屬兒子的mul之積。
此時設sum為當前3操作帶的系數,在只有加的情況下我們可以直接下傳,但是如果加乘都有,我們就需要做一點改變:
我們在下傳sum的時候,需要對每一個加操作乘上一個當前3操作內部的后綴積。
pic
如圖,+2操作要帶上*12的系數,+3操作要帶上*4的系數。
Implementation:我們先把函數按照拓撲序排序,然后用兩個函數分別實現求mul和求sum
Code:

const int N=1000010;
const int mod=998244353;
int n,m,a[N],q,f[N];
int ind[N],tp[N],tot;
struct Function {
	int opt,pos,num,mul,sum;
}c[N];
struct Edge {
	int to,nxt;
}e[N<<1];
int head[N],cnt;
inline void ade(int u,int v){
	e[++cnt].to=v,e[cnt].nxt=head[u],head[u]=cnt;
}
void Topo(){
	queue<int>q;
	for(rg int i=1;i<=m;i++)if(!ind[i])q.push(i);
	while(!q.empty()){
		int u=q.front();q.pop();
		tp[++tot]=u;
		for(rg int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			if(!--ind[v])q.push(v);
		}
	}
}
inline void GetProd(){
	for(rg int k=m;k;k--){
		int u=tp[k];
		for(rg int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			c[u].mul=c[u].mul*c[v].mul%mod;
		}
	}
}
inline void GetSum(){
	for(rg int k=1;k<=m;k++){
		int u=tp[k],suf=1;
		for(rg int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			c[v].sum=(c[v].sum+c[u].sum*suf%mod)%mod;
			suf=suf*c[v].mul%mod;
		}
	}
}
signed main(){
	Read(n);
	for(rg int i=1;i<=n;i++)Read(a[i]);
	Read(m);
	for(rg int i=1;i<=m;i++){
		Read(c[i].opt);
		if(c[i].opt==1){
			Read(c[i].pos),Read(c[i].num),c[i].mul=1;
		}else if(c[i].opt==2){
			Read(c[i].num),c[i].mul=c[i].num;
		}else {
			int cj;Read(cj),c[i].mul=1;
			for(rg int j=1,g;j<=cj;j++){
				Read(g),ade(i,g),ind[g]++;
			}
		}
	}
	Topo();GetProd();
	Read(q);
	int suf=1;//suffix product
	for(rg int i=1;i<=q;i++)Read(f[i]);
	for(rg int i=q;i;i--){
		c[f[i]].sum=(c[f[i]].sum+suf)%mod;
		suf=suf*c[f[i]].mul%mod;
	}
	GetSum();
	for(rg int i=1;i<=n;i++)a[i]=a[i]*suf%mod;
	for(rg int i=1;i<=m;i++){
		if(c[i].opt==1){
			a[c[i].pos]=(a[c[i].pos]+c[i].num*c[i].sum%mod)%mod;
		}
	}
	for(rg int i=1;i<=n;i++)cout<<a[i]<<" ";
	return 0;
}

T4 Snakes

Solution:我們簡單分析一下即可發現本題其實就是決策最強蛇吃不吃的問題,分三種情況:
第一種情況,最強蛇吃了之后還是最強的,那么它沒有危險,不吃白不吃;
第二種情況,最強蛇吃了之后不是最強也不是最弱,那么接下來的蛇吃了之后肯定比它還弱,也沒有危險,放心吃;
第三種情況,最強蛇吃了之后變為最弱蛇,此時比較復雜,我們討論一下。
假設蛇A吃了之后變為最弱蛇,此時的最強蛇蛇B如果屬於前兩種情況,蛇A就沒了,此時一定選擇不吃;
如果此時最強蛇蛇B吃了后也是最弱的,那么蛇B就要看下一條最強蛇蛇C的情況,以此類推。
這樣一直考慮下去,直到某條蛇吃了之后不是最弱蛇或者剩下兩條蛇(設為蛇X),那么蛇X會選擇吃,蛇X-1會選擇不吃,蛇X-2會吃……
也就是說,我們需要考慮最后那條蛇的奇偶性(例如:最強蛇是蛇X-1就直接停止,最強蛇是蛇X-2就吃一輪然后在蛇X-1處停止)。
整理一下,我們的決斗可以分為兩個階段:
第一階段,所有最強蛇隨便吃;
第二階段,最強蛇吃了后變成最弱蛇,需要選擇吃還是不吃,此時的決斗最多再進行一輪。
Implementation:可以用set來實現取最強最弱,但是由於復雜度\(O(\log n)\)只能得70分。
正解:使用兩個雙端隊列優化為\(O(1)\)修改。開兩個隊列\(q1,q2\)\(q1\)先賦值為原數組,然后每次取\(q1,q2\)的隊尾最大值減去\(q1\)隊頭最大值放入\(q2\)隊頭,可以證明此時\(q2\)也滿足單調性。
Code:
不放了反正也是模仿的洛谷題解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM