[CSP-S2020] 函数调用 & 贪吃蛇
函数调用
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;
}
贪吃蛇
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;
}