【比賽記錄】2025CSP-S模擬賽51
| A | B | C | D | Sum | Rank |
|---|---|---|---|---|---|
| 100 | 9 | 54 | - | 163 | 11/24 |
A. 算術
列個表格:
| \(a_i\to\) \(a_j\downarrow\) |
\(\le0\) | \(1\) | \(>1\) |
|---|---|---|---|
| \(\le0\) | ? | ? | ? |
| \(1\) | ? | ? | ? |
| \(>1\) | ? | ? | ? |
記錄當前 \(=1\)、\(>1\)、\(\ge1\) 的數量即可。
Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=1e6+5;
int n,cntge1,cnte1,cntg1;
ll a[maxn];
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n;
ll ans=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]<=0){
ans+=cntge1;
}else if(a[i]==1){
ans+=i-1;
cnte1++,cntge1++;
}else{
ans+=i-1-cntg1;
cntg1++,cntge1++;
}
// cout<<ans<<'\n';
}
cout<<ans;
return 0;
}
}
int main(){return asbt::main();}
B. 刷墻
區間 DP。設 \(f_{l,r}\) 表示區間 \([l,r]\) 的最大顏色數量。枚舉 \(k\in[l,r)\),考慮優先染一個包含了 \([k,k+1]\) 的顏色,然后再遞歸 \([l,k]\) 和 \([k+1,r]\) 的子問題。二維前綴和查一下即可。
Code
#include<bits/stdc++.h>
#define il inline
#define lwrb lower_bound
using namespace std;
namespace asbt{
int n,ll[305],rr[305],lsh[605],tot,f[605][605],s[605][605];
il int get(int l1,int l2,int r1,int r2){
return s[l2][r2]-s[l1-1][r2]-s[l2][r1-1]+s[l1-1][r1-1];
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>ll[i]>>rr[i];
lsh[++tot]=ll[i];
lsh[++tot]=rr[i];
}
sort(lsh+1,lsh+tot+1);
tot=unique(lsh+1,lsh+tot+1)-lsh-1;
for(int i=1;i<=n;i++){
s[lwrb(lsh+1,lsh+tot+1,ll[i])-lsh][lwrb(lsh+1,lsh+tot+1,rr[i])-lsh]++;
}
for(int i=1;i<=tot;i++){
for(int j=1;j<=tot;j++){
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
for(int len=2;len<=tot;len++){
for(int l=1,r=len;r<=tot;l++,r++){
for(int p=l;p<r;p++){
f[l][r]=max(f[l][r],f[l][p]+f[p+1][r]+(get(l,p,p+1,r)>0));
}
}
}
cout<<f[1][tot];
return 0;
}
}
int main(){return asbt::main();}
C. 重復
我們要找的實際上是一段形如 AABCAB 的字符串,不妨考慮枚舉第二個 A 的開頭 \(i\) 和第三個 A 的開頭 \(j\)。對于以它們開頭的最長公共前綴,對第一個 B 的開頭位置的貢獻是這樣的(先不考慮第一個 A 的限制):

于是我們預處理最長公共前綴,然后對于每一個 \(i\) 去做兩遍前綴和即可。至于第一個 A 的限制,再用哈希判斷一下就好了。時間復雜度 \(O(n^2)\)。
Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define ull unsigned ll
using namespace std;
namespace asbt{
const int maxn=5e3+5;
const ull bas1=13331;
const ll bas2=13327,mod2=1e9+7;
int n,len[maxn][maxn];
ull ha1[maxn],pw1[maxn];
ll ha2[maxn],pw2[maxn],cnt[maxn];
string s;
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>s;
n=s.size(),s=" "+s;
pw1[0]=pw2[0]=1;
for(int i=1;i<=n;i++){
pw1[i]=pw1[i-1]*bas1;
pw2[i]=pw2[i-1]*bas2%mod2;
ha1[i]=ha1[i-1]*bas1+s[i];
ha2[i]=(ha2[i-1]*bas2+s[i])%mod2;
}
for(int i=n;i;i--){
for(int j=n;j>i;j--){
if(s[i]==s[j]){
len[i][j]=min(len[i+1][j+1]+1,j-i-1);
}
}
}
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cnt[j]=0;
}
for(int j=i+1;j<=n;j++){
cnt[len[i][j]]++;
}
for(int j=n;j;j--){
cnt[j]+=cnt[j+1];
}
for(int j=n;j;j--){
cnt[j]+=cnt[j+1];
}
for(int j=1;j<i;j++){
if(ha1[i+j-1]-ha1[i-1]==(ha1[i-1]-ha1[i-j-1])*pw1[j]&&(ha2[i+j-1]-ha2[i-1]+mod2)%mod2==(ha2[i-1]-ha2[i-j-1]+mod2)*pw2[j]%mod2){
ans+=cnt[j+1];
}
}
}
cout<<ans;
return 0;
}
}
int main(){return asbt::main();}
D. 公交
首先將題意進行一個轉化。考慮我們一開始只有一個點,即樹根,然后一層層地往下走,選擇 \(u\) 能使答案減小 \(sz_u\)。因此我們要做的就是一個長鏈剖分,取前 \(k\) 大的即可。
考慮換根,發現發生變化的長鏈只有 \(O(1)\) 條,于是用 multiset 維護即可。時間復雜度 \(O(n\log n)\)。
標簽:implementation
Code
#include<bits/stdc++.h>
#define int long long
#define il inline
#define pb push_back
using namespace std;
namespace asbt{
const int maxn=2e5+5;
int n,m,a[maxn],sz[maxn],dis[maxn];
int mx1[maxn],mx2[maxn],hes[maxn];
int ans[maxn],sum;
bool top[maxn];
vector<int> e[maxn];
multiset<int> s1,s2;
il void insert(int x){
if(!x){
return ;
}
sum+=x,s1.insert(x);
if(s1.size()>m){
sum-=*s1.begin();
s2.insert(*s1.begin());
s1.erase(s1.begin());
}
}
il void erase(int x){
if(!x){
return ;
}
if(s1.find(x)!=s1.end()){
sum-=x,s1.erase(s1.find(x));
if(s2.size()){
sum+=*s2.rbegin();
s1.insert(*s2.rbegin());
s2.erase(prev(s2.end()));
}
}else{
s2.erase(s2.find(x));
}
}
il void dfs1(int u,int fa){
sz[u]=a[u];
for(int v:e[u]){
if(v==fa){
continue;
}
dfs1(v,u);
sz[u]+=sz[v];
dis[u]+=dis[v]+sz[v];
if(mx1[v]+sz[v]>=mx1[u]){
mx2[u]=mx1[u],mx1[u]=mx1[v]+sz[v];
top[hes[u]]=0,top[v]=1,hes[u]=v;
}else if(mx1[v]+sz[v]>=mx2[u]){
mx2[u]=mx1[v]+sz[v];
}
}
}
il void dfs2(int u,int fa){
if(!top[u]){
insert(mx1[u]+sz[u]);
}
for(int v:e[u]){
if(v==fa){
continue;
}
dis[v]=dis[u]-sz[v]*2+sz[1];
dfs2(v,u);
}
}
il void dfs3(int u,int fa){
// cout<<u<<":\n";
// cout<<s1.size()<<' '<<s2.size()<<'\n';
// for(int x:s1){
// cout<<x<<' ';
// }
// cout<<'\n';
// for(int x:s2){
// cout<<x<<' ';
// }
// cout<<'\n';
for(int v:e[u]){
if(v==fa){
continue;
}
int flag=0;
int mx1v=mx1[v],mx2v=mx2[v];
if(top[v]){
if(mx1[v]>mx2[u]+sz[1]-sz[v]){
flag=1;
erase(mx1[u]+sz[1]);
erase(mx2[u]);
insert(mx1[v]+sz[1]);
insert(mx2[u]+sz[1]-sz[v]);
if(mx2[u]+sz[1]-sz[v]>mx2[v]){
mx2[v]=mx2[u]+sz[1]-sz[v];
}
}else{
flag=2;
erase(mx1[u]+sz[1]);
erase(mx2[u]);
insert(2*sz[1]-sz[v]+mx2[u]);
insert(mx1[v]);
mx2[v]=mx1[v],mx1[v]=mx2[u]+sz[1]-sz[v];
top[hes[v]]=0;
}
}else{
flag=3;
erase(mx1[v]+sz[v]);
erase(mx1[u]+sz[1]);
insert(mx1[v]);
insert(2*sz[1]-sz[v]+mx1[u]);
mx2[v]=mx1[v];
mx1[v]=mx1[u]+sz[1]-sz[v];
top[hes[v]]=0;
}
ans[v]=dis[v]-sum+sz[1];
dfs3(v,u);
mx1[v]=mx1v,mx2[v]=mx2v;
switch(flag){
case 1:{
insert(mx1[u]+sz[1]);
insert(mx2[u]);
erase(mx1[v]+sz[1]);
erase(mx2[u]+sz[1]-sz[v]);
break;
}
case 2:{
insert(mx1[u]+sz[1]);
insert(mx2[u]);
erase(2*sz[1]-sz[v]+mx2[u]);
erase(mx1[v]);
top[hes[v]]=1;
break;
}
default:{
insert(mx1[v]+sz[v]);
insert(mx1[u]+sz[1]);
erase(mx1[v]);
erase(2*sz[1]-sz[v]+mx1[u]);
top[hes[v]]=1;
break;
}
}
}
}
int main(){
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1,u,v;i<n;i++){
cin>>u>>v;
e[u].pb(v),e[v].pb(u);
}
dfs1(1,0),dfs2(1,0);
ans[1]=dis[1]-sum+sz[1];
// for(int i=1;i<=n;i++){
// cout<<dis[i]<<' ';
// }
// cout<<'\n';
// for(int i=1;i<=n;i++){
// cout<<sz[i]<<' ';
// }
// cout<<'\n';
dfs3(1,0);
for(int i=1;i<=n;i++){
cout<<ans[i]<<' ';
}
return 0;
}
}
signed main(){return asbt::main();}

浙公網安備 33010602011771號