Good Bye 2020 題解
目前進度:A~G
一萬年沒開過 vp 了,決定來看一看。
然後開場就降智了,被 BC 連著卡。去看 DEF 發現全是傻逼題,以後被卡題我再不跳我就……就掉分唄(
然後看 G。最近這 CF 都出的什麼垃圾題啊,想起來又不難,寫又好煩……
甚至還卡空間。出字串題只開 256MB???一萬年後才過。
看起來勉強可以升點分,然而打得這麼難受的屑場給我分我也不想要……
A
容易發現答案是 \(x_j-x_i\) 的不同取值個數。
出題人給的那個值域 1e5 的 challenge,我怎麼只會 FFT 啊 /kk
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> PII; const int maxn=100010,mod=998244353; #define MP make_pair #define PB push_back #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define ROF(i,a,b) for(int i=(a);i>=(b);i--) #define MEM(x,v) memset(x,v,sizeof(x)) inline ll read(){ char ch=getchar();ll x=0,f=0; while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return f?-x:x; } inline int qmo(int x){return x+(x>>31?mod:0);} int n,a[maxn],ans; bool vis[maxn]; void clear(){ ans=0; FOR(i,0,50) vis[i]=false; } void solve(){ n=read(); FOR(i,1,n) a[i]=read(); FOR(i,1,n) FOR(j,i+1,n) if(!vis[a[j]-a[i]]) vis[a[j]-a[i]]=true,ans++; printf("%d\n",ans); clear(); } int main(){ int T=read(); while(T--) solve(); }
B
最大那個肯定 +1。
次大那個如果 +1 後不等於最大值也要 +1,否則不動。
以此類推。注意相等的數的細節。
出題人給的 challenge 是不是也是儘可能加就行了啊 /fad
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> PII; const int maxn=100010,mod=998244353; #define MP make_pair #define PB push_back #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define ROF(i,a,b) for(int i=(a);i>=(b);i--) #define MEM(x,v) memset(x,v,sizeof(x)) inline ll read(){ char ch=getchar();ll x=0,f=0; while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return f?-x:x; } inline int qmo(int x){return x+(x>>31?mod:0);} int n,a[maxn]; void solve(){ n=read(); FOR(i,1,n) a[i]=read(); ROF(i,n,1){ if(i==n || a[i]+1!=a[i+1] && a[i]!=a[i+1]) a[i]++; } int ans=1; FOR(i,1,n-1) if(a[i]!=a[i+1]) ans++; printf("%d\n",ans); } int main(){ int T=read(); while(T--) solve(); }
C
這都想了這麼久是不是退役了?
注意到如果不存在長度為 2 和 3 的迴文子串就合法。分奇偶討論一下顯然。
然後無腦衝個 dp。
出題人給的 challenge 似乎可以衝個動態 dp,懶得想了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> PII; const int maxn=100010,mod=998244353; #define MP make_pair #define PB push_back #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define FOR(i,a,b) for(int i=(a);i<=(b);i++) #define ROF(i,a,b) for(int i=(a);i>=(b);i--) #define MEM(x,v) memset(x,v,sizeof(x)) inline ll read(){ char ch=getchar();ll x=0,f=0; while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return f?-x:x; } inline int qmo(int x){return x+(x>>31?mod:0);} int n,f[maxn][2][2]; char s[maxn]; void solve(){ scanf("%s",s+1); n=strlen(s+1); FOR(i,0,n) f[i][0][0]=f[i][0][1]=f[i][1][0]=f[i][1][1]=1e9; f[0][1][1]=0; FOR(i,1,n){ FOR(a,0,1) FOR(b,0,1) FOR(c,0,1){ if(a || ((b || s[i]!=s[i-1]) && (c || s[i]!=s[i-2]))) f[i][a][b]=min(f[i][a][b],f[i-1][b][c]+a); } } printf("%d\n",min(min(f[n][0][0],f[n][0][1]),min(f[n][1][0],f[n][1][1]))); } int main(){ int T=read(); while(T--) solve(); }
D
首先注意到,同種顏色最優解下是連通的。若不連通,可以只保留最大那個連通塊,其它的分給別的顏色。
那麼此時一個方案的總代價,是對於每個點,包含在多少個顏色的連通塊中,乘上點權的和。
這等價於一個點的鄰邊中有多少種不同的顏色。這個數不能超過這個點的度數,且至少為 1。
那麼每次貪心取最大的就行了。顯然可以還原出一種方案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=100010,mod=998244353;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
char ch=getchar();ll x=0,f=0;
while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
inline int qmo(int x){return x+(x>>31?mod:0);}
int n,w[maxn],deg[maxn],tmp[maxn],tl;
ll ans;
void clear(){
FOR(i,1,n) deg[i]=0;
tl=ans=0;
}
void solve(){
n=read();
FOR(i,1,n) w[i]=read();
FOR(i,1,2*n-2) deg[read()]++;
FOR(i,1,n) ans+=w[i];
printf("%lld ",ans);
FOR(i,1,n) FOR(j,1,deg[i]-1) tmp[++tl]=w[i];
sort(tmp+1,tmp+tl+1,greater<int>());
FOR(i,1,n-2){
ans+=tmp[i];
printf("%lld ",ans);
}
puts("");
clear();
}
int main(){
int T=read();
while(T--) solve();
}
E
直接列舉 \(j\),然後變成求 \(a_i\&a_j\) 和 \(a_i|a_j\) 的和。
按位討論,沒了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=555555,mod=1000000007;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
char ch=getchar();ll x=0,f=0;
while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
inline int qmo(int x){return x+(x>>31?mod:0);}
int n,sum[maxn];
ll a[maxn];
void solve(){
n=read();
FOR(i,1,n) a[i]=read();
FOR(i,0,59) sum[i]=0;
FOR(i,1,n) FOR(j,0,59) if((a[i]>>j)&1) sum[j]=(sum[j]+(1ll<<j))%mod;
int ans=0;
FOR(i,1,n){
int s1=0,s2=0;
FOR(j,0,59) if((a[i]>>j)&1){
s1=(s1+sum[j])%mod;
s2=(s2+(1ll<<j)%mod*n)%mod;
}
else{
s2=(s2+sum[j])%mod;
}
ans=(ans+1ll*s1*s2)%mod;
}
printf("%d\n",ans);
}
int main(){
int T=read();
while(T--) solve();
}
F
題面完美描述了線性基的構造過程,現在只需要快速模擬即可。
容易發現,任意時候,線性基中的元素,和正在插入的元素(可能已經被消了幾次),1 的位數不超過 2。
對於目前在插入的元素,直接找到它的最大位對應的基底。如果不存在直接上去,如果存在就異或一下繼續。
然而這個複雜度還是平方級別的。可以被下面這個卡掉:
11000
01100
00110
00011
插入 10000
要解決這個問題也不難。複雜度會被卡是因為異或之後,新多出來的位對應的基底可能也存在。
所以每次加入了基底,就對前面的基底回消。那麼每個基底,除了最高位,對應的基底一定不存在。那麼每次就只有常數次操作。
要回消的基底數量可能很多,可以用並查集實現。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=555555,mod=1000000007;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
char ch=getchar();ll x=0,f=0;
while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
inline int qmo(int x){return x+(x>>31?mod:0);}
struct vec{
int len,x[2],id;
vec(){len=x[0]=x[1]=id=0;}
}a[maxn],b[maxn];
int n,m,tmp[maxn],tl,fa[maxn];
inline int qpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod;
return ans;
}
inline int getfa(int x){
return x==fa[x]?x:fa[x]=getfa(fa[x]);
}
int main(){
n=read();m=read();
FOR(i,1,n){
a[i].len=read();
FOR(j,0,a[i].len-1) a[i].x[j]=read();
sort(a[i].x,a[i].x+a[i].len,greater<int>());
a[i].id=i;
}
FOR(i,1,m) fa[i]=i;
FOR(i,1,n){
while(a[i].len){
// printf("try %d %d %d\n",a[i].len,a[i].x[0],a[i].x[1]);
int now=a[i].x[0];
if(!b[now].len){
b[now]=a[i];
break;
}
a[i].x[0]=a[i].x[1];
a[i].x[1]=0;
a[i].len--;
if(b[now].len==2){
a[i].len++;
a[i].x[a[i].len-1]=getfa(b[now].x[1]);
sort(a[i].x,a[i].x+a[i].len,greater<int>());
if(a[i].len==2 && a[i].x[0]==a[i].x[1]) a[i]=vec();
}
}
if(a[i].len==2){
int now=a[i].x[0],to=a[i].x[1];
fa[getfa(now)]=to;
}
// printf("a[i].len=%d,getfa(2)=%d\n",a[i].len,getfa(2));
}
FOR(i,1,m) if(b[i].len) tmp[++tl]=b[i].id;
sort(tmp+1,tmp+tl+1);
printf("%d %d\n",qpow(2,tl),tl);
FOR(i,1,tl) printf("%d ",tmp[i]);
}
/*
3 3
2 2 3
2 1 2
2 3 1
*/
看了官方題解,發現似乎建個圖就不用考慮那麼多東西了?
(話說只有兩個位我還沒想到建圖,那我可真是沒救了
G
先求出所有長度 \(\le 10^6\) 的 \(s_i\)(設為 \(s_0\dots,s_{mx}\)),顯然 \(mx=O(\log)\),且長度和也為線性。
詢問串 \(w\) 在 \(s_i\) 出現多少次,如果 \(|s_i|\le 10^6\) 就隨便搞了,我選擇了離線後 AC 自動機。然後就卡空間卡到自閉。
否則,有兩種可能:\(w\) 跨過 \(t_{i-1}\) 或者 \(w\) 完全在 \(s_{i-1}\) 中出現。
這可以用 \(w\) 跨過 \(t_j(mx<j\le i-1)\) 的次數和 \(w\) 完全在 \(s_{mx+1}\) 中出現的次數表示。後者也是離線後 AC 自動機。
前者直接雜湊,看 \(w\) 的字首和 \(s_{mx+1}\) 的字尾是否一樣。然後求個字首和。(然後你發現又要一個 \(n|\Sigma|\) 的陣列,慢慢卡吧)
居然寫上 4k 了。
官方題解好像沒這麼垃圾,到時候研究一下,寫就算了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn=1111111,mod=1000000007,bs1=61,bs2=251,mod1=1004535809,mod2=999911659,hhh=1000000;
#define MP make_pair
#define PB push_back
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline ll read(){
char ch=getchar();ll x=0,f=0;
while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return f?-x:x;
}
inline int qmo(int x){return x+(x>>31?mod:0);}
int n,q,mx,len[22],ans[maxn],cnt,id[maxn],fail[maxn],que[maxn],h,r,sss[maxn],x[maxn],fl,ch[maxn][26];
int pre1[maxn*2],pre2[maxn*2],suf1[maxn*2],suf2[maxn*2];
char s0[maxn],s[maxn*2],t[maxn],str[maxn*2];
bool ok[maxn];
struct fuck_the_mle{
int at,pos,id;
bool operator <(const fuck_the_mle &f)const{
if(at!=f.at) return at<f.at;
return pos<f.pos;
}
}fff[maxn];
inline int qpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) ans=1ll*ans*a%mod;
return ans;
}
void insert(const char *s,int d){
int now=0,l=strlen(s+1);
FOR(i,1,l){
int p=s[i]-'a';
if(!ch[now][p]) ch[now][p]=++cnt;//,printf("add %d\n",cnt);
now=ch[now][p];
}
id[d]=now;
}
void build(){
h=1;r=0;
FOR(i,0,25) if(ch[0][i]) que[++r]=ch[0][i];
while(h<=r){
int now=que[h++];
FOR(i,0,25) if(ch[now][i]){
fail[ch[now][i]]=ch[fail[now]][i];
que[++r]=ch[now][i];
}
else ch[now][i]=ch[fail[now]][i];
}
}
void work(int vs){
// printf("work %d\n",vs);
FOR(i,1,cnt) sss[i]=0;
int now=0,l=strlen(s+1);
FOR(i,1,l){
int p=s[i]-'a';
now=ch[now][p];
sss[now]++;
// printf("add at %d\n",now);
}
ROF(i,r,1) sss[fail[que[i]]]=(sss[fail[que[i]]]+sss[que[i]])%mod;
// FOR(i,1,cnt) printf("%d ",sss[i]);
// puts("");
int tmp=qpow(2,mod-1-vs);
FOR(i,1,q) if(vs==min(mx,x[i])) ans[i]=(ans[i]+1ll*sss[id[i]]*tmp)%mod;
// FOR(i,1,q){
// printf("%lld ",1ll*ans[i]*qpow(2,x[i])%mod);
// }
// puts("");
}
int main(){
n=read();q=read();
scanf("%s%s",s0+1,t+1);
len[0]=strlen(s0+1);
strcpy(s+1,s0+1);
FOR(i,1,n){
mx=i;
strcpy(str+1,s+1);
s[len[i-1]+1]=t[i];
strcat(s+1,str+1);
len[i]=2*len[i-1]+1;
if(len[i]>=hhh) break;
}
FOR(i,1,len[mx]){
pre1[i]=(1ll*pre1[i-1]*bs1+s[i]-'a')%mod1;
pre2[i]=(1ll*pre2[i-1]*bs2+s[i]-'a')%mod2;
}
int pr1=1,pr2=1;
ROF(i,len[mx],1){
suf1[i]=(suf1[i+1]+1ll*(s[i]-'a')*pr1)%mod1;
suf2[i]=(suf2[i+1]+1ll*(s[i]-'a')*pr2)%mod2;
pr1=1ll*pr1*bs1%mod1;
pr2=1ll*pr2*bs2%mod2;
}
/* FOR(i,mx+1,n){
FOR(j,0,25) sum[i][j]=sum[i-1][j];
sum[i][t[i]-'a']=(sum[i][t[i]-'a']+qpow(2,mod-1-i))%mod;
}*/
FOR(_,1,q){
x[_]=read();
scanf("%s",str+1);
int l=strlen(str+1);
insert(str,_);
if(x[_]<=mx || l>len[mx]) continue;
FOR(i,1,l) ok[i]=true;
int hs1=0,hs2=0;
FOR(i,1,l-1){
hs1=(1ll*hs1*bs1+str[i]-'a')%mod1;
hs2=(1ll*hs2*bs2+str[i]-'a')%mod2;
ok[i+1]&=hs1==suf1[len[mx]-i+1] && hs2==suf2[len[mx]-i+1];
}
hs1=hs2=0;
int pr1=1,pr2=1;
ROF(i,l,2){
hs1=(hs1+1ll*(str[i]-'a')*pr1)%mod1;
hs2=(hs2+1ll*(str[i]-'a')*pr2)%mod2;
ok[i-1]&=hs1==pre1[l-i+1] && hs2==pre2[l-i+1];
pr1=1ll*pr1*bs1%mod1;
pr2=1ll*pr2*bs2%mod2;
}
FOR(i,1,l) if(ok[i]) fff[++fl]=(fuck_the_mle){str[i]-'a',x[_],_};
// FOR(i,1,l) if(ok[i]) ans[_]=(ans[_]+sum[x[_]][str[i]-'a'])%mod;
}
sort(fff+1,fff+fl+1);
int cur=1;
FOR(i,0,25){
while(cur<=fl && fff[cur].at<i) cur++;
int sum=0;
FOR(j,mx+1,n){
if(t[j]-'a'==i) sum=(sum+qpow(2,mod-1-j))%mod;
while(cur<=fl && fff[cur].at==i && fff[cur].pos<j) cur++;
while(cur<=fl && fff[cur].at==i && fff[cur].pos==j){
ans[fff[cur].id]=(ans[fff[cur].id]+sum)%mod;
cur++;
}
}
}
build();
MEM(s,0);
strcpy(s+1,s0+1);
work(0);
FOR(i,1,n){
strcpy(str+1,s+1);
s[len[i-1]+1]=t[i];
strcat(s+1,str+1);
len[i]=2*len[i-1]+1;
// printf("%s\n",s+1);
work(i);
if(len[i]>=hhh) break;
}
FOR(i,1,q){
ans[i]=1ll*ans[i]*qpow(2,x[i])%mod;
printf("%d\n",ans[i]);
}
}
H
看都沒看。這麼長的題面先咕著。
I
互動壓軸?跑路了。