CSP-S2 2020
\(A\)
认真阅读题面,仔细调试大模拟,手动构造数据检查,赛后\(FST\)即可。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define fi first
#define se second
#define ll long long
ll nff[500];
template <class T>
void Read(T &x)
{
x = 0; ll p = 0; char st = getchar();
while (st < '0' || st > '9') p = (st == '-'), st = getchar();
while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
x = p ? -x : x;
return;
}
void File()
{
freopen("julian.in", "r", stdin);
freopen("julian.out", "w", stdout);
}
pair<ll, ll> Work1(ll tmp)
{
if (tmp <= 31) return make_pair(1, tmp);
if (31 < tmp && tmp <= 59) return make_pair(2, tmp - 31);
if (59 < tmp && tmp <= 90) return make_pair(3, tmp - 59);
if (90 < tmp && tmp <= 120) return make_pair(4, tmp - 90);
if (120 < tmp && tmp <= 151) return make_pair(5, tmp - 120);
if (151 < tmp && tmp <= 181) return make_pair(6, tmp - 151);
if (181 < tmp && tmp <= 212) return make_pair(7, tmp - 181);
if (212 < tmp && tmp <= 243) return make_pair(8, tmp - 212);
if (243 < tmp && tmp <= 273) return make_pair(9, tmp - 243);
if (273 < tmp && tmp <= 304) return make_pair(10, tmp - 273);
if (304 < tmp && tmp <= 334) return make_pair(11, tmp - 304);
if (334 < tmp && tmp <= 365) return make_pair(12, tmp - 334);
}//平年的处理
pair<ll, ll> Work2(ll tmp)
{
if (tmp <= 31) return make_pair(1, tmp);
if (31 < tmp && tmp <= 60) return make_pair(2, tmp - 31);
if (60 < tmp && tmp <= 91) return make_pair(3, tmp - 60);
if (91 < tmp && tmp <= 121) return make_pair(4, tmp - 91);
if (121 < tmp && tmp <= 152) return make_pair(5, tmp - 121);
if (152 < tmp && tmp <= 182) return make_pair(6, tmp - 152);
if (182 < tmp && tmp <= 213) return make_pair(7, tmp - 182);
if (213 < tmp && tmp <= 244) return make_pair(8, tmp - 213);
if (244 < tmp && tmp <= 274) return make_pair(9, tmp - 244);
if (274 < tmp && tmp <= 305) return make_pair(10, tmp - 274);
if (305 < tmp && tmp <= 335) return make_pair(11, tmp - 305);
if (335 < tmp && tmp <= 366) return make_pair(12, tmp - 335);
}//闰年的处理
pair<ll, ll> Work3(ll tmp)
{
if (tmp <= 30) return make_pair(1, tmp + 1);
if (30 < tmp && tmp <= 59) return make_pair(2, tmp - 30);
if (59 < tmp && tmp <= 90) return make_pair(3, tmp - 59);
if (90 < tmp && tmp <= 120) return make_pair(4, tmp - 90);
if (120 < tmp && tmp <= 151) return make_pair(5, tmp - 120);
if (151 < tmp && tmp <= 181) return make_pair(6, tmp - 151);
if (181 < tmp && tmp <= 212) return make_pair(7, tmp - 181);
if (212 < tmp && tmp <= 243) return make_pair(8, tmp - 212);
if (243 < tmp && tmp <= 273) return make_pair(9, tmp - 243);
if (273 < tmp && tmp <= 304) return make_pair(10, tmp - 273);
if (304 < tmp && tmp <= 334) return make_pair(11, tmp - 304);
if (334 < tmp && tmp <= 365) return make_pair(12, tmp - 334);
}//最开始一年的处理
bool Rn(ll x)
{
if (x % 400 == 0 || (x % 4 == 0 && x % 100 != 0)) return 1;
return 0;
}
void Prework()
{
for (ll i = 1; i <= 400; i++)
if (Rn(i)) nff[i] = nff[i - 1] + 366;
else nff[i] = nff[i - 1] + 365;
return;
}
template <class T>
void Print(T x)
{
if (x > 9) Print(x / 10);
putchar(x % 10 + '0');
return;
}
int main()
{
// File();
Prework();
ll q, r;
Read(q);
while (q--)
{
Read(r);
if (r <= 1721423)
{
ll nf = 4713;
if (r > 365) r -= 365;
else
{
pair<ll, ll> tmp = Work3(r);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(nf); putchar(' '); puts("BC");
// printf("%lld %lld %lld BC\n", tmp.se, tmp.fi, nf);
continue;
}
nf -= (r / 1461) * 4;
if (r % 1461 == 0) nf += 4;
ll tmpr = r;
r -= (tmpr / 1461) * 1461;
if (tmpr % 1461 == 0) r = 1461;
ll tmp = 0;
for(int i = 1; i <= 3; i++) if(r > 365) r -= 365, nf--, tmp++;
if (tmp == 3)
{
pair<ll, ll> tmp = Work2(r);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(nf - 1); putchar(' '); puts("BC");
// printf("%lld %lld %lld BC\n", tmp.se, tmp.fi, nf - 1);
continue;
}
else
{
pair<ll, ll> tmp = Work1(r);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(nf - 1); putchar(' '); puts("BC");
// printf("%lld %lld %lld BC\n", tmp.se, tmp.fi, nf - 1);
continue;
}
}//如果是公元前
else
{
if (r <= 2299160)
{
r -= 1721423;
ll nf = 0;
nf += (r / 1461) * 4;
if (r % 1461 == 0) nf -= 4;
ll tmpr = r;
r -= (tmpr / 1461) * 1461;
if (tmpr % 1461 == 0) r = 1461;
ll tmp = 0;
for (int i = 1; i <= 3; i++) if(r > 365) r -= 365, nf++, tmp++;
if (tmp == 3)
{
pair<ll, ll> tmp = Work2(r);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(nf + 1);puts("");
//printf("%lld %lld %lld\n", tmp.se, tmp.fi, nf + 1);
continue;
}
else
{
pair<ll, ll> tmp = Work1(r);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(nf + 1);puts("");
// printf("%lld %lld %lld\n", tmp.se, tmp.fi, nf + 1);
continue;
}
}//如果是儒略历
else
{
r -= 2299160;
if (r <= 78)
{
if (r <= 17)
{
Print(15 + r - 1); putchar(' '); Print(10); putchar(' '); Print(1582);puts("");
// printf("%lld %d %d\n", 15 + r - 1, 10, 1582);
continue;
}
r -= 17;
if (r <= 30)
{ Print(r); putchar(' '); Print(11); putchar(' '); Print(1582); puts("");
// printf("%lld %d %d\n", r, 11, 1582);
continue;
}
r -= 30;
Print(r); putchar(' '); Print(12); putchar(' '); Print(1582); puts("");
//printf("%lld %d %d\n", r, 12, 1582);
continue;
}
else
{
r -= 78;
if (r <= 6575)
{
ll tmpp = 0, lst = 0;
for (ll j = 1583; j <= 1600; j++)
{
lst = tmpp;
if (Rn(j)) tmpp += 366;
else tmpp += 365;
if (tmpp >= r)
{
if (Rn(j))
{
pair<ll, ll> tmp = Work2(r - lst);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(j); puts("");
// printf("%lld %lld %lld\n", tmp.se, tmp.fi, j);
}
else
{
pair<ll, ll> tmp = Work1(r - lst);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(j); puts("");
// printf("%lld %lld %lld\n", tmp.se, tmp.fi, j);
}
break;
}
}
continue;
}
else
{
r -= 6575;
ll nf = 1600;
nf += (r / 146097) * 400;
if (r % 146097 == 0) nf -= 400;
ll tmpr = r;
r -= (tmpr / 146097) * 146097;
if (tmpr % 146097 == 0) r = 146097;
ll nftmp = lower_bound(nff + 1, nff + 400 + 1, r) - nff;
nf += nftmp;
if (Rn(nf))
{
pair<ll, ll> tmp = Work2(r - nff[nftmp - 1]);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(nf); puts("");
// printf("%lld %lld %lld\n", tmp.se, tmp.fi, nf);
}
else
{
pair<ll, ll> tmp = Work1(r - nff[nftmp - 1]);
Print(tmp.se); putchar(' '); Print(tmp.fi); putchar(' '); Print(nf); puts("");
// printf("%lld %lld %lld\n", tmp.se, tmp.fi, nf);
}
}
}
}//格利高里厉
}//如果是公元后
}
return 0;
}
\(B\)
由于每一位需要的饲料互不相同,所以直接用\(cnt\)数组记录需要的饲料个数,如果当前饲料可行就使所有需要它的那一位的\(cnt\)减一,最后\(cnt\)数组为\(0\)的位置都可以选,设一共有\(num\)个位置为\(0\),答案就是\(2^{num} - n\)。
\(k = 64, n = 0\)会爆\(unsigned\ long\ long\),要特判输出字符串。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#define ll unsigned long long
const int N = 1000000;
int n, m, c, now, b[N + 50], cwq, p[N + 50], q[100], cnt[100];
ll id, a[N + 50], k;
template <class T>
void Read(T &x)
{
x = 0; int p = 0; char st = getchar();
while (st < '0' || st > '9') p = (st == '-'), st = getchar();
while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
x = p ? -x : x;
return;
}
void File()
{
freopen("zoo.in", "r", stdin);
freopen("zoo.out", "w", stdout);
}
struct Tmp
{
int a, b;
} tmp[N + 50];
int main()
{
// File();
Read(n); Read(m); Read(c); Read(k);
id = (1LL << k) - 1;
for (int i = 1; i <= n; i++) Read(a[i]);
for (int i = 1; i <= m; i++)
{
Read(tmp[i].a); Read(tmp[i].b); b[++cwq] = tmp[i].b;
cnt[tmp[i].a]++;
}
ll now = 0;
for (int i = 1; i <= n; i++) now = now | a[i];
for (ll j = 0; j < k; j++) if ((now >> j) & 1) q[j] = 1;
sort(b + 1, b + cwq + 1);
cwq = unique(b + 1, b + cwq + 1) - b - 1;
for (int i = 1; i <= m; i++) tmp[i].b = lower_bound(b + 1, b + cwq + 1, tmp[i].b) - b, p[tmp[i].b] |= q[tmp[i].a];
for (int i = 1; i <= m; i++) if (p[tmp[i].b]) cnt[tmp[i].a]--;
ll ans = 0;
int num = 0;
for (int i = 0; i < k; i++)
{
if (!cnt[i])
{
if (!ans) ans = 1;
ans = ans * 2LL;
num++;
}
}
if (num == 64 && n == 0) puts("18446744073709551616");
else cout << ans - n << endl;
return 0;
}
\(C\)
每个函数不会调用自身所以是张\(Dag\),发现如果没有乘法或者没有加法都是好计算的,放在一起的时候可以把加法的两部分分开考虑,某个时刻加一个数就相当于最后时刻加上这个数乘所有在这个操作之后发生的乘一个数的操作,所以需要知道某个加法操作之后的所有乘法操作的乘积,在\(Dag\)上\(dp\)即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 1e5;
const int MOD = 998244353;
int n, a[N + 50], m, ask, dp[N + 50], ans, tp[N + 50], mul = 1, cnt[N + 50], in[N + 50], cwq, b[N + 50], finalmul = 1;
struct OP
{
int op, p, v;
vector<int> hs;
} opt[N + 50];
void Read(int &x)
{
x = 0; int p = 0; char st = getchar();
while (st < '0' || st > '9') p = (st == '-'), st = getchar();
while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
x = p ? -x : x;
return;
}
void Qm(int &x)
{
x -= MOD;
x += x >> 31 & MOD;
return;
}
queue<int> q;
void Solve()
{
for (int i = 1; i <= m; i++) if (!in[i]) q.push(i);
while (!q.empty())
{
int u = q.front(); q.pop();
tp[++cwq] = u;
int siz = opt[u].hs.size() - 1;
for (int i = siz; i >= 0; i--)
{
int v = opt[u].hs[i];
in[v]--;
if (!in[v]) q.push(v);
}
}
for (int i = m; i >= 1; i--)
{
int u = tp[i];
if (opt[u].op == 2) cnt[u] = opt[u].v;
else cnt[u] = 1;
int siz = opt[u].hs.size() - 1;
for (int j = siz; j >= 0; j--)
{
int v = opt[u].hs[j];
cnt[u] = 1LL * cnt[u] * cnt[v] % MOD;
}
}
// for (int i = 1; i <= m; i++) printf("%d %d\n", dp[i], cnt[i]);
dp[m] = 1;
for (int i = 1; i <= m; i++)
{
int siz = opt[tp[i]].hs.size() - 1, u = tp[i], tmp = 1;
for (int j = siz; j >= 0; j--)
{
int v = opt[u].hs[j];
Qm(dp[v] += 1LL * tmp * dp[u] % MOD);
tmp = 1LL * tmp * cnt[v] % MOD;
}
}
finalmul = cnt[m];
for (int i = 1; i <= m; i++)
if (opt[i].op == 1) Qm(b[opt[i].p] += 1LL * opt[i].v * dp[i] % MOD);
return;
}
int main()
{
// freopen("call3.in", "r", stdin);
Read(n);
for (int i = 1; i <= n; i++) Read(a[i]);
Read(m);
for (int i = 1; i <= m; i++)
{
Read(opt[i].op);
if (opt[i].op == 1) Read(opt[i].p), Read(opt[i].v);
else
{
if (opt[i].op == 2) Read(opt[i].v);
else
{
Read(opt[i].v);
for (int j = 1, x; j <= opt[i].v; j++) Read(x), opt[i].hs.push_back(x), in[x]++;
}
}
}
m++;
int ask; Read(ask); opt[m].v = ask; opt[m].op = 3;
for (int i = 1, x; i <= ask; i++) Read(x), opt[m].hs.push_back(x), in[x]++;
Solve();
for (int i = 1; i <= n; i++) Qm(b[i] += 1LL * a[i] * finalmul % MOD);
for (int i = 1; i <= n; i++) printf("%d ", b[i]);
return 0;
}
\(D\)
如果一条蛇吃了之后不会变成最小的,那么如果下一条蛇吃的话生命值会小于等于它,后来肯定打不过它,这是因为\((max - min, i)\)是单调递减的;如果下一条蛇不吃,那么游戏结束,当前蛇也不会被吃,所以如果一条蛇吃了某条蛇之后不是最小的就可以一直吃。
如果吃了之后变成最小的,那么就看下一条蛇敢不敢吃,如果下一条蛇敢吃,那么当前蛇选择不吃游戏结束;如果下一条蛇不敢吃,那么当前蛇吃,游戏也结束。
一条蛇敢吃当它吃了最小的不是最小的蛇或者它的下一条不敢吃,一条蛇不敢吃当它的吓一跳敢吃,这样递归判定即可。
注意到因为\((max - min, i)\)有很好的单调性质,所以可以像蚯蚓一样开两个队列动态维护最大最小值。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1000000;
int a[N + 50], n, head1, tail1, head2, tail2;
void Read(int &x)
{
x = 0; int p = 0; char st = getchar();
while (st < '0' || st > '9') p = (st == '-'), st = getchar();
while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
x = p ? -x : x;
return;
}
struct Node
{
int qz, id;
bool operator > (const Node &rhs) const
{
if (qz == rhs.qz) return id > rhs.id;
return qz > rhs.qz;
}
bool operator < (const Node &rhs) const
{
if (qz == rhs.qz) return id < rhs.id;
return qz < rhs.qz;
}
Node operator - (const Node &rhs) const
{
return (Node){qz - rhs.qz, id};
}
bool operator == (const Node &rhs) const
{
return (qz == rhs.qz) && (id == rhs.id);
}
} q1[N + 50], q2[N + 50];
void Print(Node a)
{
printf("%d %d\n", a.qz, a.id);
}
int Check()
{
Node maxx, minn;
if (head1 > tail1)
{
maxx = q2[head2], minn = q2[tail2];
head2++; tail2--;
}
else
{
if (head2 > tail2)
{
maxx = q1[head1], minn = q1[tail1];
head1++; tail1--;
}
else
{
maxx = max(q1[head1], q2[head2]);
minn = min(q1[tail1], q2[tail2]);
if (head1 <= tail1 && maxx == q1[head1]) head1++; else head2++;
if (head1 <= tail1 && minn == q1[tail1]) tail1--; else tail2--;
}
}
if (head1 > tail1 && head2 > tail2) return 1;
Node minnn = (Node){0x7fffffff, 0x7fffffff};
if (head1 <= tail1) minnn = min(minnn, q1[tail1]);
if (head2 <= tail2) minnn = min(minnn, q2[tail2]);
Node tmp = maxx - minn;
if (tmp > minnn) return 1;
q2[++tail2] = tmp;
return !Check();
}
int Solve()
{
head1 = head2 = 1; tail1 = tail2 = 0;
for (int i = n; i >= 1; i--) q1[++tail1] = ((Node){a[i], i});
int ans = n;
while (tail1 - head1 + 1 + tail2 - head2 + 1 >= 2)
{
Node maxx, minn;
if (head1 > tail1)
{
maxx = q2[head2], minn = q2[tail2];
head2++; tail2--;
}
else
{
if (head2 > tail2)
{
maxx = q1[head1], minn = q1[tail1];
head1++; tail1--;
}
else
{
maxx = max(q1[head1], q2[head2]);
minn = min(q1[tail1], q2[tail2]);
if (head1 <= tail1 && maxx == q1[head1]) head1++; else head2++;
if (head1 <= tail1 && minn == q1[tail1]) tail1--; else tail2--;
}
}
if (head1 > tail1 && head2 > tail2)
{
ans--;
break;
}
Node minnn = (Node){0x7fffffff, 0x7fffffff};
if (head1 <= tail1) minnn = min(minnn, q1[tail1]);
if (head2 <= tail2) minnn = min(minnn, q2[tail2]);
Node tmp = maxx - minn;
if (tmp > minnn)
{
ans--;
q2[++tail2] = tmp;
continue;
}
q2[++tail2] = tmp;
if (!Check()) ans--;
break;
}
return ans;
}
int main()
{
int t, k;
Read(t);
t--;
Read(n);
for (int i = 1; i <= n; i++) Read(a[i]);
printf("%d\n", Solve());
while (t--)
{
Read(k);
for (int i = 1, x, y; i <= k; i++) Read(x), Read(y), a[x] = y;
printf("%d\n", Solve());
}
return 0;
}