1. 程式人生 > 其它 >[CSP-S2020] 函式呼叫 & 貪吃蛇

[CSP-S2020] 函式呼叫 & 貪吃蛇

函式呼叫

link

Solution

不知道一年之前我在想什麼,明明很sb的一個題目哎。。。

可以想到的是,我們如果可以計算出一個增加節點會貢獻多少次就可以直接算了。整體乘的貢獻也算在這裡就好了。直接topo排序算出進入一個塊之前已經全域性成了多少就好了。

Code

#include <bits/stdc++.h>>
using namespace std;
 
#define Int register int
#define mod 998244353
#define MAXN 100005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

vector <int> g1[MAXN],g2[MAXN];
int n,m,tp[MAXN],ris[MAXN],val[MAXN],pos[MAXN],cnt[MAXN],sum[MAXN],deg[MAXN];

int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
void Add (int &a,int b){a = add (a,b);}
void Sub (int &a,int b){a = dec (a,b);}

void topo1 (){
	queue <int> q;
	for (Int i = 0;i <= m;++ i){
		deg[i] = g1[i].size();
		if (!deg[i]) q.push (i);
	}
	while (!q.empty()){
		int u = q.front();q.pop ();
		for (Int v : g2[u]){
			sum[v] = mul (sum[v],sum[u]);
			if (!(-- deg[v])) q.push (v);
		}
	}
}

void topo2 (){
	queue <int> q;
	for (Int i = 0;i <= m;++ i){
		deg[i] = g2[i].size();
		if (!deg[i]) q.push (i);
	}
	while (!q.empty()){
		int u = q.front(),hav = 1;q.pop (),reverse (g1[u].begin(),g1[u].end());
		for (Int v : g1[u]){
			Add (cnt[v],mul (cnt[u],hav)),hav = mul (hav,sum[v]);
			if (!(-- deg[v])) q.push (v);
		}
	}
}

signed main(){
	read (n);
	for (Int i = 1;i <= n;++ i) read (val[i]);
	read (m),sum[0] = cnt[0] = 1;
	for (Int i = 1;i <= m;++ i){
		read (tp[i]),sum[i] = 1;
		if (tp[i] == 1) read (pos[i],ris[i]);
		else if (tp[i] == 2) read (sum[i]);
		else{
			int len;read (len);
			for (Int k = 1,v;k <= len;++ k) read (v),g1[i].push_back (v),g2[v].push_back (i); 
		}
	}
	int Q;read (Q);
	for (Int i = 1,x;i <= Q;++ i) read (x),g1[0].push_back (x),g2[x].push_back (0);
	topo1 (),topo2 ();
	for (Int i = 1;i <= n;++ i) val[i] = mul (val[i],sum[0]);
	for (Int i = 1;i <= m;++ i) if (tp[i] == 1) Add (val[pos[i]],mul (ris[i],cnt[i]));
	for (Int i = 1;i <= n;++ i) write (val[i]),putchar (' ');putchar ('\n');
	return 0;
}

貪吃蛇

link

Solution

考慮對於當前狀況,如果最大值吃掉最小值之後不是最小值,那麼它就一定會吃掉。因為後面的次大值吃掉之後的最小值一定不必當前最大值減去當前最小值大,後面同理,所以肯定吃不掉,那它就一定會吃。

那麼如果吃掉之後是最小值就需要考慮。考慮吃掉了,那麼如果次大值吃掉了吃了小魚的大雨不是最小值,那最大值就不能吃,否則就可以。然後依次類推,找到第一個最大值吃掉不是最小值的,然後判斷過程吃的個數的奇偶性即可。

似乎可以用雙端佇列做到 \(\Theta(nT)\),但是我比較懶,所以就只寫了 \(\Theta(Tn\log n)\)

Code

#include <bits/stdc++.h>>
using namespace std;
 
#define Int register int
#define MAXN 1000005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

int n,a[MAXN];

#define pii pair<int,int>
#define se second
#define fi first

void Work (){
	set <pii> S;
	for (Int i = 1;i <= n;++ i) S.insert ({a[i],i});
	if (n == 3){
		if (a[3] - a[1] < a[2]) puts ("3");
		else puts ("1");
	}
	else{
		while (S.size() >= 2){
			auto it1 = S.begin(),it2 = S.end();-- it2;
			if (S.size() == 2){
				puts ("1");
				return ;
			}
			pii f1 = *it1,f2 = *it2,New = {f2.fi - f1.fi,f2.se};
			S.erase (it1),S.erase (it2);
			if ((*S.begin()) < New) S.insert (New);
			else{
				S.insert (f1),S.insert (f2);
				break;
			}
		}
		int fuc = 1,cnt = S.size();
		while (S.size() >= 2){
			if (S.size() == 2){
				fuc ++;
				break;
			}
			else{
				auto it1 = S.begin(),it2 = S.end();-- it2;
				pii f1 = *it1,f2 = *it2,New = {f2.fi - f1.fi,f2.se};S.erase (it1),S.erase (it2);
				if (New < (*S.begin())) fuc ++,S.insert (New);
				else{
					fuc ++;
					break;
				}
			}
		}
		write (cnt - (!(fuc & 1))),putchar ('\n');
	}
}

signed main(){
//	freopen ("snakes4.in","r",stdin);
	int T;read (T);
	read (n);
	for (Int i = 1;i <= n;++ i) read (a[i]);
	Work (),T --;
	while (T --> 0){
		int k;read (k);
		for (Int i = 1,p,v;i <= k;++ i) read (p,v),a[p] = v;
		Work ();
	}
	return 0;
}