CSP2020-S 游记
10.11 CSP-S1
自从国庆假期回到学校我申请停课,
从此开始了长达近一个的停课生活。
初赛也是有惊无险地过去了。
一出来发现自己仍旧是大考必败型选手,
对了答案发现我其实错了挺多的,
可能是因为错的都是分值高的吧,
要不是某题好像有歧义补加分,
我应该就连80都没有了
11.4 Day-2
考前最后一次模拟赛,难度就特别离谱:
T1:斯坦纳树+Spfa(原题还是道紫题)
T2:LCA+树上差分(不过这题出的挺好的)
T3:DP+NTT(想法很妙,但有了NTT显然就离谱)
T4:四维偏序(建议不做)
11.5-11.6 Day-1至Day0
这两天在背板:
字符串:AC自动机、Manacher、最小表示法。
数论:线性基
数据结构:点分治、扫描线
11.7 CSP-S2
早上本来想写题的,但害怕下午考砸,就没写了
四个小时的时间其实非常的短,有一说一
前一个半小时在写T1,然后再用了一个小时写T2(主要是读题能力太差了)
剩下两个小时,去写了T4,大概花了一个小时写了个伪七十分代码。
然后T3看懂题目没时间写了,但是至少那个下传加法的想法特别妙
后续
估分: 100+100+0+70
自测: 100+95+0+20
快结束的时候让T4只能过第一个子任务,
然后还没有发现要特判\(2^{64}\)
但是所有网站都是一样的分数估计就稳了
CCF出成绩仍然是215,
wtcl,就只配被吊打,应该先写T3的,说不定就能想到正解了
洛谷 7075 [CSP-S2020] 儒略日
代码(大模拟)
#include <cstdio>
#include <cctype>
using namespace std;
const int lim=2298884,LIM=1721424,st=4713;
const int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
typedef long long lll; lll n; int ans,Q;
inline lll iut(){
lll ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline int calc(int x){
int ans=(st-x+1)*365+1;
if (st-x<13){
for (int i=x;i<st;++i)
if ((i&3)==1) ++ans;
return ans;
}
if ((x&3)<2) ++ans;
x=(x+3)/4*4;
return ans+(st-x)/4;
}
inline int calc2(int x){
return x*365+x/4;
}
inline void Get_Print(int A,int B,int C){
print(A),putchar(32),print(B),putchar(32),print(C);
}
inline void BC(){
putchar(32),putchar(66),putchar(67);
}
inline void Grego(int n,int year,int z){
int ans;
if (n<=31){
Get_Print(n,1,year);
return;
}
else if (n<=59){
Get_Print(n-31,2,year);
return;
}
bool flag=(year&3)==z;
if (n==60&&flag){
Get_Print(n-31,2,year);
return;
}
n-=59+flag;
for (ans=3;ans<13;++ans)
if (n>month[ans]){
n-=month[ans];
}else break;
if (ans>12) --year,ans=1;
Get_Print(n,ans,year);
}
inline lll calc3(int x){
lll ans=1ll*(x-1584)*365+(x-1584)/4;
if (x>1600) ans+=(x-1600)/400-(x-1600)/100;
return ans;
}
inline void juli(int year){
int ans;
if (n<=31){
Get_Print(n,1,year);
return;
}
else if (n<=59){
Get_Print(n-31,2,year);
return;
}
bool flag=((year%100)&&((year&3)==0))||((year%400)==0);
if (n==60&&flag){
Get_Print(n-31,2,year);
return;
}
n-=59+flag;
for (ans=3;ans<13;++ans)
if (n>month[ans]){
n-=month[ans];
}else break;
Get_Print(n,ans,year);
}
int main(){
//freopen("julian.in","r",stdin);
//freopen("julian.out","w",stdout);
Q=iut();
for (int j=1;j<=Q;++j,putchar(10)){
n=iut()+1;
if (n<=LIM){
int l=1,r=st;
while (l<r){
int mid=(l+r+1)>>1;
if (calc(mid)>=n) l=mid;
else r=mid-1;
}
if (l^st) n-=calc(l+1);
if (((l&3)==3)&&l<4700) ++n;
Grego(n,l,1),BC();
}else if (n<=lim){
n-=LIM;
int l=1,r=1581;
while (l<r){
int mid=(l+r)>>1;
if (calc2(mid)>=n) r=mid;
else l=mid+1;
}
if (l>1) n-=calc2(l-1);
Grego(n,l,0);
}else{
n-=lim;
if (n<=273){
int ans;
for (ans=1;ans<10;++ans)
if (n>month[ans]) n-=month[ans];
else break;
Get_Print(n,ans,1582);
}else if (n<=277) Get_Print(n-273,10,1582);
if (n<=277) continue;
n-=277;
if (n<=17) Get_Print(n+14,10,1582);
else{
n-=17;
if (n<=30){
Get_Print(n,11,1582);
}else if (n<=61){
Get_Print(n-30,12,1582);
}else{
n-=61;
if (n<=365) Grego(n,1583,0);
else if (n<=731) Grego(n-365,1584,0);
else{
n-=731;
int l=1585,r=1e9;
while (l<r){
int mid=(l+r)>>1;
if (calc3(mid)>=n) r=mid;
else l=mid+1;
}
if (l^1585) n-=calc3(l-1);
juli(l);
}
}
}
}
}
return 0;
}
洛谷 7076 [CSP-S2020] 动物园
分析
如果某个二进制位没有在已饲养的动物中出现那么这个二进制位不能选,注意特判 \(2^{64}\)
代码
#include <cstdio>
#include <cctype>
using namespace std;
typedef unsigned long long ull;
ull n,m,now,tot,v[71],ans=1;
inline ull iut(){
ull ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
int main(){
n=iut(),m=iut(),iut(),tot=iut();
for (int i=1;i<=n;++i) now|=iut();
for (int i=1;i<=m;++i){
int x=iut(); iut();
if (v[x]) continue;
if (!((now>>x)&1))
v[x]=1,--tot;
}
for (int i=0;i<tot;++i) ans*=2;
if (!n&&!ans) return !printf("18446744073709551616");
return !printf("%llu",ans-n);
}
洛谷 7077 [CSP-S2020] 函数调用
分析
可以将 \(Q\) 次调用当作一个函数也就是求这个函数的值,
可以发现按照这样调用实际上是一个有向无环图的结构。
实际上的修改就是全局乘一个数以及每个加法操作乘上对应的数
将乘法标记上传,再将加法标记下传,最后就是每个加法的统计
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=100011,mod=998244353; struct node{int y,next;}e[N*10];
int deg[N],q[N],wl[N],a[N],opt[N],X[N],now=1,ww[N],as[N],et,n,m,Q,b[N],ws[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed mo(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline void add(int x,int y){++deg[y],e[++et]=(node){y,as[x]},as[x]=et;}
inline void Topsort(){
rr int head=1,tail=0;
for (rr int i=1;i<=m;++i)
if (!deg[i]) q[++tail]=i;
while (head<=tail){
rr int x=q[head++];
for (rr int j=as[x];j;j=e[j].next)
if (--deg[e[j].y]==0) q[++tail]=e[j].y;
}
}
inline void pup(){
for (rr int i=m;i;--i)
for (rr int j=as[q[i]];j;j=e[j].next)
wl[q[i]]=1ll*wl[q[i]]*wl[e[j].y]%mod;
}
inline void pdown(){
for (rr int i=1;i<=m;++i)
for (rr int j=as[q[i]],t=1;j;j=e[j].next)
ws[e[j].y]=mo(ws[e[j].y],1ll*ws[q[i]]*t%mod),
t=1ll*t*wl[e[j].y]%mod;
}
signed main(){
n=iut(); for (rr int i=1;i<=n;++i) a[i]=iut();
m=iut();
for (rr int i=1;i<=m;++i)
switch (opt[i]=iut()){
case 1:{
X[i]=iut(),ww[i]=iut(),wl[i]=1;
break;
}
case 2:ww[i]=wl[i]=iut(); break;
case 3:{
wl[i]=1;
for (rr int o=iut();o;--o)
add(i,iut());
break;
}
}
Topsort(),pup(),Q=iut();
for (rr int i=1;i<=Q;++i) b[i]=iut();
for (rr int i=Q;i;--i)
ws[b[i]]=mo(ws[b[i]],now),now=1ll*now*wl[b[i]]%mod;
pdown();
for (rr int i=1;i<=n;++i) a[i]=1ll*a[i]*now%mod;
for (rr int i=1;i<=m;++i) if (opt[i]==1)
a[X[i]]=mo(a[X[i]],1ll*ww[i]*ws[i]%mod);
for (rr int i=1;i<=n;++i) print(a[i]),putchar(32);
return 0;
}
洛谷 7078 [CSP-S2020] 贪吃蛇
分析
如果最强的蛇吃了最弱的蛇后没有变成最弱蛇那它一定会吃。
否则最强的蛇变成最弱的蛇时考虑下一条最强蛇会不会变成最弱蛇,
实际上如果一直轮下去直到最强蛇不是最弱蛇那么最强蛇一定会吃掉最弱蛇,
这样最强蛇吃不吃只与最后一条最强蛇与其距离的奇偶性决定。
由于吃掉最弱蛇之后结束前最强蛇仍然具有单调性,所以用两个队列维护即可
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
using namespace std;
const int N=1000011;
pair<int,int>q0[N],q1[N],MX,MN;
int h0,h1,t0,t1,flag=1,n,tot,F,a[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline signed answ(){
h0=h1=1,t0=n,tot=t1=0,F=-1;
for (rr int i=1;i<=n;++i) q0[n-i+1]=make_pair(a[i],i);
for (rr int i=n-1;i;--i){
if (h0>t0||(h1<=t1&&q0[h0]<q1[h1])) MX=q1[h1++]; else MX=q0[h0++];
if (h0>t0||(h1<=t1&&q0[t0]>q1[t1])) MN=q1[t1--]; else MN=q0[t0--];
MX.first-=MN.first;
if (h0>t0||(h1<=t1&&q0[t0]>q1[t1])) MN=q1[t1]; else MN=q0[t0];
if (i>1&&MX<MN) F=(F==-1)?0:(F^1);
else if (~F) return n-F-tot;
else ++tot;
q1[++t1]=MX;
}
return n-tot;
}
signed main(){
for (rr int T=iut();T;--T){
if (flag){
n=iut(),flag=0;
for (rr int i=1;i<=n;++i) a[i]=iut();
}else{
for (rr int Q=iut(),x;Q;--Q)
x=iut(),a[x]=iut();
}
printf("%d\n",answ());
}
return 0;
}