CSP2020题解
虽然炸了,题解还是要补的
儒略日
没有什么好说的,直接模拟
(貌似官方数据比较水,所以飞过去了)
code:
#include<bits/stdc++.h>
#define PN 365
#define int long long
#define RN 366
#define N 5005
using namespace std;
int yue[15] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int yue2[15] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int sy[15], sy2[15], bcn[N];
int GLL, GYQ;
int NIAN, YUE, RI;
int calc(int x) {
return x * 365 + x / 4;
}
int calcc(int x) {
return x * 365 + x / 4 - (x / 100 - x / 400) + 12;
}
signed main() {
// freopen("julian.in","r",stdin);
// freopen("julian.out","w",stdout);
for(int i = 1; i <= 12; i ++) sy[i] = yue[i] + sy[i - 1];
for(int i = 1; i <= 12; i ++) sy2[i] = yue2[i] + sy2[i - 1];
for(int i = 4713; i >= 1; i --) {
if((i - 1) % 4 == 0) bcn[i] = RN;
else bcn[i] = PN;
}
for(int i = 4712; i >= 1; i --) bcn[i] += bcn[i + 1];
GYQ = 0;
GYQ = bcn[1];//4713 * PN + (4713 + 3) / 4 - 1;
GLL = 0;
for(int i = 1; i < 1582; i ++) {
if(i % 4 == 0) GLL += RN;
else GLL += PN;
}
GLL += sy2[9];
GLL += 4;
int n, t;
scanf("%lld", &t);
while(t --) {
scanf("%lld", &n);
n ++;
if(n <= GYQ) {
int l = 0, r = 4712;
while(l + 1 < r) {
int mid = (l + r) >> 1;
if(bcn[4713 - mid] < n) l = mid;
else r = mid;
}
if(bcn[4713 - l] < n) l ++;
NIAN = 4713 - l;
n = n - bcn[NIAN + 1];
if((NIAN - 1)% 4 == 0) {
for(int i = 1; i <= 12; i ++) {
if(sy2[i] >= n) {
YUE = i;
break;
}
}
n = n - sy2[YUE - 1];
RI = n;
} else {
for(int i = 1; i <= 12; i ++) {
if(sy[i] >= n) {
YUE = i;
break;
}
}
n = n - sy[YUE - 1];
RI = n;
}
printf("%lld %lld %lld BC\n", RI, YUE, NIAN);
} else {
n = n - GYQ;
if(n <= GLL) {
int l = 0, r = 1582;
while(l + 1 < r) {
int mid = (l + r) >> 1;
if(calc(mid) >= n) r = mid;
else l = mid;
}
NIAN = r;
n = n - calc(NIAN - 1);
if(NIAN % 4 == 0) {
for(int i = 1; i <= 12; i ++) {
if(sy2[i] >= n) {
YUE = i;
break;
}
}
n = n - sy2[YUE - 1];
RI = n;
} else {
for(int i = 1; i <= 12; i ++) {
if(sy[i] >= n) {
YUE = i;
break;
}
}
n = n - sy[YUE - 1];
RI = n;
}
printf("%lld %lld %lld\n", RI, YUE, NIAN);
} else { //printf("*");
//printf("%lld %lld\n", n, GLL);
n += 10;
int l = 1581, r = 1e9 + 3;
while(l + 1 < r) {
int mid = (l + r) >> 1;
if(calcc(mid) >= n) r = mid;
else l = mid;
}
NIAN = r;
n = n - calcc(NIAN - 1);
if((NIAN % 4 == 0 && NIAN % 100 != 0) || (NIAN % 400 == 0)) {
for(int i = 1; i <= 12; i ++) {
if(sy2[i] >= n) {
YUE = i;
break;
}
}
n = n - sy2[YUE - 1];
RI = n;
} else {
for(int i = 1; i <= 12; i ++) {
if(sy[i] >= n) {
YUE = i;
break;
}
}
n = n - sy[YUE - 1];
RI = n;
}
printf("%lld %lld %lld\n", RI, YUE, NIAN);
}
}
}
return 0;
}
动物园
好像耶没什么难度吧
code:
#include<bits/stdc++.h>
#define N 1000005
#define ull unsigned long long
using namespace std;
struct Q {
int x, y;
} q[N];
int n, m, c, k, col[85], anss[85], tot, sl[N];
ull a[N];
ull read() {
ull x = 0;
char ch = getchar();
for(;ch <'0' || ch > '9';) ch = getchar();
for(;ch >= '0' && ch <= '9';) x = x * 10 + (ch - '0'), ch = getchar();
return x;
}
int main() {
//scanf("%d%d%d%d", &n, &m, &c, &k);
// freopen("zoo.in","r",stdin);
//freopen("zoo.out","w",stdout);
ios::sync_with_stdio(false);
n = read(), m = read(), c = read(), k = read();
for(int i = 1; i <= n; i ++) {
a[i] = read();
ull x = a[i];
for(int i = 0; i < k; i ++) {
if((x >> i) & 1) col[i] = 1;
}
}
for(int i = 1; i <= m; i ++) {
int x, y;
x = read(), y = read();
q[i].x = x, q[i].y = y;
if(col[x]) sl[++ tot] = y;
}
sort(sl + 1, sl + 1 + tot);
for(int i = 1; i <= m; i ++) {
int x = q[i].x, y = q[i].y;
if(!col[x]) {
int pos = lower_bound(sl + 1, sl + 1 + tot, y) - sl;
if(sl[pos] != y) {
anss[x] = 1;
}
}
}
ull ans = 1, ss = 0;
for(int i = 0; i < k; i ++)
if(!anss[i]) ans = ans * 2, ss ++;
ans = ans - n;
if(ss == 64 && !n) cout << "18446744073709551616";
else cout << ans;
return 0;
}
函数调用
考场上一直在刚最后一题,这题只花了5min写了个暴力
考完发现还是一个挺妙的题
首先考虑一个加法操作
+
a
+a
+a,如果后面有一个乘法操作
∗
b
*b
∗b,那就相当于加上了
+
a
∗
b
+a*b
+a∗b
记
m
l
[
i
]
ml[i]
ml[i]为第i个操作做完后所有数被乘了多少,最后肯定是所有数
∗
m
l
[
m
+
1
]
+
某
个
值
*ml[m+1]+某个值
∗ml[m+1]+某个值
那个值就是所有在那个位置的加法产生的贡献,记
p
a
d
[
i
]
pad[i]
pad[i]表示第
i
i
i个操作如果对之前的操作的加法产生的乘法贡献(后面的乘法贡献之和)
然后这个操作加的值就是
v
∗
p
a
d
[
i
]
v* pad[i]
v∗pad[i]
p
a
d
[
i
]
pad[i]
pad[i]就是所有后缀乘的和(拓扑图上的)
然后直接拓扑排序
code:
#include<bits/stdc++.h>
#define N 2000005
#define int long long
#define mod 998244353
using namespace std;
int n, m, ml[N], a[N], pad[N], vis[N], in[N], ad[N];
vector<int> g[N], pml[N];
queue<int> qq;
struct Q {
int opt, pos, v;
} q[N];
void dfs(int u) {
vis[u] = 1;
ml[u] = (q[u].opt == 2)? ml[u] = q[u].v : 1;
for(int i = 0; i < g[u].size(); i ++) {
pml[u].push_back(ml[u]);
int v = g[u][i];
if(!vis[v]) dfs(v);
ml[u] = ml[u] * ml[v] % mod;
}
}
void tuopu() {
for(int i = 1; i <= m + 1; i ++) if(vis[i])
for(int j = 0; j < g[i].size(); j ++) {
int v = g[i][j];
in[v] ++;
}
for(int i = 1; i <= m + 1; i ++) if(!in[i] && vis[i]) qq.push(i), pad[i] = 1;
while(qq.size()) {
int u = qq.front(); qq.pop();
if(q[u].opt == 1)
(ad[q[u].pos] += q[u].v * pad[u] % mod) %= mod;
for(int i = 0; i < g[u].size(); i ++) {
int v = g[u][i];
(pad[v] += pad[u] * pml[u][i] % mod) %= mod;
if(!(-- in[v])) qq.push(v);
}
}
}
signed main() {
scanf("%lld", &n);
for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
scanf("%lld", &m);
for(int i = 1; i <= m + 1; i ++) {
if(i <= m) scanf("%lld", &q[i].opt);
else q[i].opt = 3;
if(q[i].opt == 1) scanf("%lld%lld", &q[i].pos, &q[i].v);
else if(q[i].opt == 2) scanf("%lld", &q[i].v);
else {
int k;
scanf("%lld", &k);
while(k --) {
int x = 0;
scanf("%lld", &x);
g[i].push_back(x);
}
}
}
for(int i = 1; i <= m + 1; i ++) reverse(g[i].begin(), g[i].end());
ml[m + 1] = 1; dfs(m + 1);
tuopu();
for(int i = 1; i <= n; i ++) printf("%lld ", (a[i] * ml[m + 1] % mod + ad[i]) % mod);
return 0;
}
贪吃蛇
摘自:https://www.luogu.com.cn/blog/wcsb/solution-p7078
推出了一些简单的性质后模拟这个过程就行了
code:
#include<bits/stdc++.h>
#define N 2000005
#define mp make_pair
#define pr pair<int, int>
using namespace std;
deque<pair<int, int> > q1, q2;
int n, a[N], t;
pr mx() {//取最大
pr o;
if(!q2.size() || q1.size() && q1.back() > q2.back()) o = q1.back(), q1.pop_back();
else o = q2.back(), q2.pop_back();
return o;
}
int main() {
scanf("%d", &t);
for(int cas = 1; cas <= t; cas ++) {
while(q1.size()) q1.pop_back();
while(q2.size()) q2.pop_back();
int k;
scanf("%d", &k);
if(cas == 1) n = k;
if(cas == 1) for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
else {
for(int i = 1; i <= k; i ++) {
int x, y;
scanf("%d%d", &x, &y);
a[x] = y;
}
}
for(int i = 1; i <= n; i ++) q1.push_back(mp(a[i], i));
int ans = 0;
while(1) {
if(q1.size() + q2.size() == 2) {
ans = 1;
break;
}
int x = 0, id = 0, y = 0;
y = q1.front().first, q1.pop_front();
pr o = mx();
x = o.first, id = o.second;
pr now = mp(x - y, id);
if(!q1.size() || q1.front() > now) {//第二阶段
ans = q1.size() + q2.size() + 2;
int dep = 0;
while(1) {
dep ++;
if(q1.size() + q2.size() == 1) {
ans -= !(dep & 1);
break;
}
pr o = mx();
int x = o.first, id = o.second;
now = mp(x - now.first, id);
if((!q1.size() || now < q1.front()) && (!q2.size() || now < q2.front())) {
;
} else {
ans -= !(dep & 1);
break;
}
}
break;
} else {
q2.push_front(now);//第一阶段
}
}
printf("%d\n", ans);
}
return 0;
}
总体来说题目质量还行吧