CSP-S2020题目整理

T1 儒略日

这道题目在考场上卡爆我

然后我就废了

这道题实际上就是考察一个对于闰年和平年的研究

我们可以先预处理前四百年的情况,然后对于在1582年之前的和1582年之后的分类讨论一下,然后这样就可以直接加减了

用一个函数来返回月份的天数似乎比较方便

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#define int long long
using namespace std;
const int maxn=146097;
int q;
int y[maxn],m[maxn],d[maxn];
int r,tmp;
int calc(int year,int month)
{
if(month==2)
{
if(year%4!=0) return 28;
else
{
if(year%100!=0) return 29;
else
{
if(year%400!=0) return 28;
else return 29;
}
}
}
if(month==4||month==6||month==9||month==11)
return 30;
else return 31;
}
signed main()
{
m[0]=d[0]=1;
for(int i=1;i<maxn;i++)
{
d[i]=d[i-1]+1;
m[i]=m[i-1];
y[i]=y[i-1];
if(d[i]>calc(y[i],m[i]))
{
m[i]++,d[i]=1;
}
if(m[i]>12)
{
y[i]++;
m[i]=1;
}
}
cin>>q;
while(q--)
{
cin>>r;
if(r>2299160)
{
r-=2159351;
tmp=r/maxn*400+1200;
r%=maxn;
}
else
{
tmp=r/1461*4-4712;
r%=1461;
}
cout<<d[r]<<" "<<m[r]<<" ";
if(tmp+y[r]>0)
cout<<tmp+y[r];
else
cout<<(1-tmp-y[r])<<" BC";
cout<<'\n';
}
return 0;
}

T2 动物园

这道题目我当年在考场看到之后直接就没有去做,没错是的

然后我就光荣爆零了

现在看来,实际上就只是一个位运算的应用,然后题目看起来比较可怕罢了,然后我们的对于这道题

可以用一个数字来记录一下动物的数量,然后需要买的饲料的情况,用二进制就好了

然后我们统计所有的情况,用容斥原理,减去不能怨的动物的数量,剩下的就是还能选的动物的数量啦

注意用一个unsigned long long 和特判

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#define int unsigned long long
using namespace std;
int n,m,c,k;
int ans,dw,ls;
signed main()
{
cin>>n>>m>>c>>k;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
dw|=x;
}
for(int i=1;i<=m;i++)
{
int p,q;
cin>>p>>q;
ls|=1ull<<p;
}
for(int i=0;i<k;i++)
if(!((ls>>i)&1)||((dw>>i)&1))
ans++;

if(ans==64&&n==0)
cout<<"18446744073709551616"<<'\n';//特判
else
{
if(ans==64)
cout<<-n<<'\n';
else
cout<<(1ull<<ans)-n<<'\n';
}
return 0;
}

T3 函数调用

在赛场上我一度认为这道题目是最简单的

但是不是

这道题目看到标签说要用拓扑排序来着

然后拓扑排序一下

实际上对于每个操作进行处理,对于操作2,实际上我们可以看成若干个操作1,然后操作3也可以转化一下,然后我们就可以建一个函数调用关系的有向图,进行拓扑排序,看函数调用的顺序,然后我们对于每一个加法和乘法,看他们对于总的答案的贡献是多少,然后就可做了

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
const int maxn=100005;
const int mod=998244353;
int n,m,q;
int cnt[maxn];
int a[maxn];
int type[maxn],mul[maxn],add[maxn],pos[maxn];
int out1[maxn],out2[maxn];
vector<int> g1[maxn],g2[maxn];
void topo1()
{
queue <int> q;
for(int i=0;i<=m;i++)
{
out1[i]=g2[i].size();
if(out1[i]==0)
q.push(i);
}
while(q.size())
{
int x=q.front();
q.pop();
for(int i=0;i<g1[x].size();i++)
{
int e=g1[x][i];
mul[e]=1ll*mul[e]*mul[x]%mod;
out1[e]--;
if(out1[e]==0)q.push(e);
}
}
}
void topo2()
{
queue <int> q;
for(int i=0;i<=m;i++)
{
out2[i]=g1[i].size();
if(out2[i]==0)
q.push(i);
}
while(q.size())
{
int x=q.front();
int tag=1;
q.pop();
for(int i=g2[x].size();i>0;--i)
{
int e=g2[x][i-1];
cnt[e]=(cnt[e]+1ll*cnt[x]*tag)%mod;
tag=1ll*tag*mul[e]%mod;
out2[e]--;
if(out2[e]==0)
q.push(e);
}
}
}
int main()
{
std::ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
cin>>m;
mul[0]=1;
for(int i=1;i<=m;i++)
{
cin>>type[i];
if(type[i]==1)
{
mul[i]=1;
cin>>pos[i]>>add[i];
}
if(type[i]==2)
cin>>mul[i];
if(type[i]==3)
{
mul[i]=1;
int c;
cin>>c;
for(int j=0;j<c;++j)
{
int e;
cin>>e;
g1[e].push_back(i);
g2[i].push_back(e);
}
}
}
cin>>q;
cnt[0]=1;
while(q--)
{
int x;
cin>>x;
g1[x].push_back(0);
g2[0].push_back(x);
}
topo1();
topo2();
for(int i=1;i<=n;i++)
a[i]=1ll*a[i]*mul[0]%mod;
for(int i=1;i<=m;i++)
{
if(type[i]==1)
a[pos[i]]=(a[pos[i]]+1ll*cnt[i]*add[i])%mod;
}
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
return 0;
}

T4 贪吃蛇

讲一个笑话,这是我当初以为整场比赛第二简单的题目

然后我就和这道题目搏斗,与这道题目抗争

最终的结果是我壮烈牺牲

这道题虽然用我的申必贪心方法,样例都能过,但是最后还是爆零了

然后现在看了题解之后,还是有一点懵的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
const int maxn=1000005;
const int inf=1e9;
int T,n,a[maxn];
pair <int,int> q1[maxn],q2[maxn];
int l1,r1,l2,r2;
pair <int,int> get_max()//取最大蛇
{
if(r1==l1)
return q2[l2++];
else if(r2==l2)
return q1[--r1];
else if(q2[l2]>q1[r1-1])
return q2[l2++];
else return q1[--r1];
}
pair <int,int> get_min()//取最小
{
if(l1==r1)
return q2[--r2];
else if(r2==l2)
return q1[l1++];
else if(q2[r2-1]<q1[l1])
return q2[--r2];
else return q1[l1++];
}
pair <int,int> Min(pair <int,int> x,pair <int,int> y)
{
return x<y?x:y;
}
inline void solve()
{
l1=r1=l2=r2=0;
for(int i=1;i<=n;++i)
q1[r1++]=make_pair(a[i],i);
int flag=0,cnt=0,alf=0;
while(1)
{
cnt++;
pair <int,int> x=get_min(),y=get_max();
pair <int,int> z=Min((l1<r1?q1[l1]:make_pair(inf,-inf)),(l2<r2?q2[r2-1]:make_pair(inf,-inf)));
y.first-=x.first;
if(y>z||cnt==n-1)
{
if(flag)
{
cout<<n-(flag-(alf&1))<<'\n';
return ;
}
if(cnt==n-1)
{
cout<<1<<'\n';
return ;
}
q2[r2++]=y;
}
else
{
alf++;
if(!flag)
flag=cnt;
q2[r2++]=y;
}
}
}
int main()
{
cin>>T;
T--;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
solve();
while(T--)
{
int k;
cin>>k;
for(int i=1;i<=k;i++)
{
int x;
cin>>x;
cin>>a[x];
}
solve();
}
return 0;
}