比赛名称:OCPC 2025 Winter Day 8: Zagreb Contest 2
时间:2026-07-27
当场过题数:\(4\)

赛后补题数:\(1\)

共计通过题数:\(5\)
\(\text{K}\)
找出一个长为 \(2n\) 的合法括号序列,所有左括号所在位置可以对答案贡献 \(a_i\),最大化答案。
DP 跑不过去,我们考虑根据性质贪心。
发现假如前面的数比后面的大,那肯定选前面的比选后面的优。
那我们从最劣的情况 \(()()\cdots()()\) 开始,从后往前逐步调整,按上述法则进行替换即可得出最优方案。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=500005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int n;
int a[Mx];
bool vis[Mx];
void Solve(){
n=read();
for(int i=1;i<=n+n;i++){
a[i]=read();
vis[i]=0;
}
reverse(a+1,a+n+n+1);
priority_queue<pii,vector<pii>,greater<pii> >q;
for(int i=1;i<=n+n;i++){
if(i%2==0){
q.push({a[i],i});
}
else{
if(!q.empty()&&a[i]>=q.top().fi){
q.pop();
q.push({a[i],i});
}
}
}
while(!q.empty()){
vis[q.top().se]=1;
//
q.pop();
}
for(int i=n+n;i>=1;i--) if(vis[i]) printf("%lld ",n+n-i+1);
puts("");
}
signed main(){
int T=read();
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{J}\)
随机在两 \(01\) 串中为 \(0\) 的位置填入 \(A,B\) 个 \(1\),问最后两个串做或运算结果的二进制中 \(1\) 的个数。
这是期望线性性裸题,我们只需求出通过两种方式使得每一个位置最终是 \(1\) 的概率相加即可。
这里在 double 意义下,除以零会得到 INF,不会 RE,完全不必特判。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=500005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int n;
int A,B;
string s,t;
void Solve(){
n=read();
A=read(),B=read();
cin>>s>>t;
int cA=count(s.begin(),s.end(),'0');
int cB=count(t.begin(),t.end(),'0');
double pA=1.0*A/cA;
double pB=1.0*B/cB;
double ans=0;
for(int i=0;i<n;i++){
bool oA=s[i]-'0';
bool oB=t[i]-'0';
if(oA||oB) ans++;
else ans+=1.0-(1.0-pA)*(1.0-pB);
}
printf("%.10lf",ans);
}
signed main(){
int T=1;
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{H}\)
求字符串删去一个字符得到的 \(n\) 个串的字典序中位串。
对于字典序,我们可以采取逐位确定的思路。
关键性质是答案的第 \(i\) 位只可能有两种取值,要么是原字符串的第 \(i\) 位,要么是第 \(i+1\) 位。
那么我们只需要去判断这一个位置到底是哪种取值就可以了。
维护方式多种多样,我这里选用树状数组,反正 T 不了。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
using namespace std;
const int Mx=1000005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int n,mid;
string s;
bool ban[Mx];
char Rank(int i,int id){
if(id<i) return s[id];
else return s[id+1];
}
int t[Mx];
void Add(int i){
for(;i<=n;i+=(i&-i)) t[i]++;
}
int Qry(int i){
int res=0;
for(;i;i&=(i-1)) res+=t[i];
return res;
}
void Solve(){
cin>>s;
n=s.length();
s=" "+s;
mid=(n+1)/2;
string ans;
set<int>rem;
for(int i=1;i<=n;i++) ban[i]=0,t[i]=0,rem.insert(i);
for(int id=1;id<n;id++){
int cnt[26]={0};
char w='#';
cnt[s[id]-'a']+=n-id-Qry(n)+Qry(id);
cnt[s[id+1]-'a']+=id-Qry(id);
// for(int i=id+1;i<=n;i++) +=1-ban[i];
// for(int i=1;i<=id;i++) cnt[s[id+1]-'a']+=1-ban[i];
for(int c=0;c<26;c++){
if(mid>cnt[c]) mid-=cnt[c];
else{
w='a'+c;
ans+=w;
break;
}
}
if(w=='#') exit(114);
vector<int>kll;
if(s[id]!=w){
if(rem.empty()) continue;
for(auto it=prev(rem.end());;){
int i=*it;
if(i<=id) break;
kll.push_back(i);
ban[i]=1;
Add(i);
if(it==rem.begin()) break;
it=prev(it);
}
//for(int i=id+1;i<=n;i++) ban[i]=1;
}
if(s[id+1]!=w){
if(rem.empty()) continue;
for(auto it=rem.begin();it!=rem.end();it=next(it)){
int i=*it;
if(i>id) break;
kll.push_back(i);
ban[i]=1;
Add(i);
}
//for(int i=1;i<=id;i++) ban[i]=1;
}
for(int i:kll) rem.erase(i);
//for(int i=1;i<=n;i++) if(Rank(i,id)!=w) ban[i]=1;
}
cout<<ans<<endl;
}
signed main(){
int T=read();
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{C}\)
给出若干合法三元集合,问是否可以构造一个长度不为 \(3\) 的倍数的环使得任意三个相连位置的数所构成的集合都是一个合法集合。
可以把最后构造出来的那个环上移动的过程看作是在合法集合之间跳跃的过程,这启示我们建图。
我们把一个点视为一个有序数对,两个点之间可以转移当且仅当这个数对的两个元素和下个数对的第一个元素所构成的集合为一个合法集合。
由此,对于每个三元合法集合,我们可以构造出 \(6\) 条有向边。
现在问是否存在一个长度不为 \(3\) 的倍数的环。
我们参考二分图的判定方法,用三种颜色在 dfs 过程中依次循环地给节点染色。
假如染色无法正确完成,则说明存在这样的环;否则所有环的环长均为 \(3\) 的倍数,无解。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=2000005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int n;
int No_;
map<pii,int>id;
vector<int>e[Mx];
int col[Mx];
void dfs(int u){
for(int v:e[u]){
if(!col[v]){
//cout<<u<<" -> "<<v<<endl;
col[v]=(1+col[u])%3+1;
dfs(v);
}
}
}
void Solve(){
n=read();
No_=0;
id.clear();
for(int i=1,a,b,c;i<=n;i++){
a=read(),b=read(),c=read();
if(!id[{a,b}]) id[{a,b}]=++No_;
if(!id[{b,a}]) id[{b,a}]=++No_;
if(!id[{a,c}]) id[{a,c}]=++No_;
if(!id[{c,a}]) id[{c,a}]=++No_;
if(!id[{c,b}]) id[{c,b}]=++No_;
if(!id[{b,c}]) id[{b,c}]=++No_;
e[id[{a,b}]].push_back(id[{b,c}]);
e[id[{b,a}]].push_back(id[{a,c}]);
e[id[{a,c}]].push_back(id[{c,b}]);
e[id[{c,a}]].push_back(id[{a,b}]);
e[id[{c,b}]].push_back(id[{b,a}]);
e[id[{b,c}]].push_back(id[{c,a}]);
}
for(int u=1;u<=No_;u++) if(!col[u]) col[u]=1,dfs(u);
bool no=1;
//for(int u=1;u<=No_;u++) cout<<u<<" : "<<col[u]<<endl;
for(int u=1;u<=No_;u++){
for(int v:e[u]){
if(col[v]!=(1+col[u])%3+1) no=0;
}
}
if(no) puts("no");
else puts("yes");
for(int i=1;i<=No_;i++) e[i].clear(),col[i]=0;
}
signed main(){
int T=read();
while(T--) Solve();
return 0;
}
/*
Hello!!
Sample:
1
7
7 4 6
2 3 7
7 2 4
5 4 6
3 6 7
5 3 6
1 4 6
----------------
*/
\(\text{G}\)
在一个矩阵中填入 \(1,2,3,4\),求使得任意两个相邻位置的差的绝对值恰为 \(1\) 的填法的方案数。
首先考虑先把奇数偶数分开考虑,不妨先填入奇数。
那么我们发现,奇数一定填在所有下图的同色格中,不妨为浅色格。
填入奇数后,剩下的深色格必然填入偶数。那这样的偶数填入方案有多少种?
假如一个深色格周围全填了 \(3\),也就是说没有 \(1\),那么这个格有 \(2,4\) 两种可能情况,否则为一种。
那就是说去计算有有多少个深色格周围没有 \(1\)。
我们可以认为,一个 \(1\) 的填入相当于覆盖了一个 "+",即覆盖该格的上下左右——被覆盖的格填法唯一,否则为两种。一种覆盖方案对答案的贡献为各深色格填法之积。
那也就是去计算所有这样的覆盖方案的贡献之和。
根据数据范围我们考虑状压 DP。
假如我们去记录某行上面两行的数据,那再加上转移,复杂度就爆了。
那我们考虑轮廓线 DP——记录下图红点处的值。
考虑当前点(绿色位置)是否放入一个“+”时,我们去考虑蓝色问号处是否被覆盖,并进行转移。
这样复杂度是 \(O(nm2^m)\) 的,试了试跑不过去啊,怎么办。
注意到 \(n,m\) 很小,直接打表不就完了嘛!!!!!
两分钟就跑完了,很快啊!!!!!
哦,其实这个东西就是求棋盘图的独立集个数,NB。

打表程序:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=500005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int a[Mx];
int f[1<<24],g[1<<24];
signed main(){
for(int n=1;n<=24;n++){
for(int m=1;m<=n;m++){
int ans=0;
f[0]=1;
int rk=0;
for(int i=1;i<=n+1;i++){
for(int j=0;j<m;j++){
if((i+j)%2!=(n+m-1)%2) continue;
rk++;
for(int S=0;S<(1ll<<m);S++){
if(!f[S]) continue;
int Y=S|(1ll<<j),N=Y^(1ll<<j);
int cN=1;
bool q1=(j==0)||(((S>>(j-1))&1)==0);
bool q2=(((S>>j)&1)==0);
bool q3=(((S>>(j+1))&1)==0);
if(i>1&&q1&&q2&&q3) cN=2;
if(i<=n) (g[Y]+=f[S])%=p;
(g[N]+=f[S]*cN%p)%=p;
}
for(int S=0;S<(1ll<<m);S++){
//if(f[rk][S]) cout<<i<<" "<<j+1<<' '<<S<<" : "<<f[rk][S]<<endl;
f[S]=g[S],g[S]=0;
}
}
}
for(int S=0;S<(1ll<<m);S++) (ans+=f[S])%=p,f[S]=0;
(ans*=2)%=p;
printf("f[%lld][%lld]=%lld;\n",n,m,ans);
}
}
return 0;
}
/*
Hello!!
Sample:
287282346
833181761
367195929
429295212
----------------
*/
AC 代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<vector>
#include<array>
#include<random>
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mkp make_pair
#define pii pair<int,int>
#define cout cerr<<">> ",cout
using namespace std;
const int Mx=500005,p=998244353;
int read(){
int Alice=0,Aya=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') Aya=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
Alice=(Alice<<3)+(Alice<<1)+(ch^48);
ch=getchar();
}
return (Aya==1?Alice:-Alice);
}
int n,m;
int f[25][25];
signed main(){
n=read(),m=read();
if(n<m) swap(n,m);
f[1][1]=4;
f[2][1]=6;
f[2][2]=14;
f[3][1]=10;
f[3][2]=34;
f[3][3]=126;
f[4][1]=16;
f[4][2]=82;
f[4][3]=454;
f[4][4]=2468;
f[5][1]=26;
f[5][2]=198;
f[5][3]=1654;
f[5][4]=13486;
f[5][5]=110894;
f[6][1]=42;
f[6][2]=478;
f[6][3]=5998;
f[6][4]=73574;
f[6][5]=908770;
f[6][6]=11197722;
f[7][1]=68;
f[7][2]=1154;
f[7][3]=21794;
f[7][4]=401596;
f[7][5]=7458182;
f[7][6]=138100506;
f[7][7]=563769194;
f[8][1]=110;
f[8][2]=2786;
f[8][3]=79122;
f[8][4]=2191702;
f[8][5]=61169374;
f[8][6]=704359705;
f[8][7]=522815399;
f[8][8]=618646891;
f[9][1]=178;
f[9][2]=6726;
f[9][3]=287354;
f[9][4]=11961826;
f[9][5]=501832262;
f[9][6]=30523393;
f[9][7]=788921750;
f[9][8]=353269119;
f[9][9]=174651543;
f[10][1]=288;
f[10][2]=16238;
f[10][3]=1043442;
f[10][4]=65283832;
f[10][5]=123520918;
f[10][6]=300483971;
f[10][7]=657297226;
f[10][8]=814191916;
f[10][9]=255118208;
f[10][10]=778857939;
f[11][1]=466;
f[11][2]=39202;
f[11][3]=3789214;
f[11][4]=356300442;
f[11][5]=827234621;
f[11][6]=167264001;
f[11][7]=385076964;
f[11][8]=991820754;
f[11][9]=741016966;
f[11][10]=780280466;
f[11][11]=946952732;
f[12][1]=754;
f[12][2]=94642;
f[12][3]=13759958;
f[12][4]=946337561;
f[12][5]=502426749;
f[12][6]=619991054;
f[12][7]=917570473;
f[12][8]=325454888;
f[12][9]=430825940;
f[12][10]=8038478;
f[12][11]=23998860;
f[12][12]=582527565;
f[13][1]=1220;
f[13][2]=228486;
f[13][3]=49967846;
f[13][4]=630513342;
f[13][5]=438911670;
f[13][6]=982393439;
f[13][7]=783113678;
f[13][8]=988583147;
f[13][9]=447493468;
f[13][10]=562822878;
f[13][11]=257932462;
f[13][12]=162962894;
f[13][13]=641697399;
f[14][1]=1974;
f[14][2]=551614;
f[14][3]=181451998;
f[14][4]=24216528;
f[14][5]=194550940;
f[14][6]=971553657;
f[14][7]=825312059;
f[14][8]=158695724;
f[14][9]=832503467;
f[14][10]=38195780;
f[14][11]=531504379;
f[14][12]=418430059;
f[14][13]=44788716;
f[14][14]=827982241;
f[15][1]=3194;
f[15][2]=1331714;
f[15][3]=658921858;
f[15][4]=678124802;
f[15][5]=370441189;
f[15][6]=462016199;
f[15][7]=354594324;
f[15][8]=774812380;
f[15][9]=392161871;
f[15][10]=612026487;
f[15][11]=76478493;
f[15][12]=458966756;
f[15][13]=549456284;
f[15][14]=893660039;
f[15][15]=973497767;
f[16][1]=5168;
f[16][2]=3215042;
f[16][3]=396307040;
f[16][4]=341808860;
f[16][5]=709335819;
f[16][6]=167484158;
f[16][7]=818388072;
f[16][8]=500705394;
f[16][9]=81346512;
f[16][10]=584278429;
f[16][11]=584099036;
f[16][12]=849814463;
f[16][13]=472708412;
f[16][14]=857308973;
f[16][15]=374664162;
f[16][16]=357230729;
f[17][1]=8362;
f[17][2]=7761798;
f[17][3]=703199970;
f[17][4]=782338446;
f[17][5]=195986497;
f[17][6]=430761202;
f[17][7]=490533170;
f[17][8]=247537190;
f[17][9]=777268119;
f[17][10]=133678358;
f[17][11]=918693032;
f[17][12]=437393871;
f[17][13]=497023280;
f[17][14]=756493485;
f[17][15]=602296374;
f[17][16]=57762764;
f[17][17]=788134134;
f[18][1]=13530;
f[18][2]=18738638;
f[18][3]=608057123;
f[18][4]=353923685;
f[18][5]=143388044;
f[18][6]=361911456;
f[18][7]=204072071;
f[18][8]=486273918;
f[18][9]=86949;
f[18][10]=519170342;
f[18][11]=340309251;
f[18][12]=954730931;
f[18][13]=33442112;
f[18][14]=439044100;
f[18][15]=937864143;
f[18][16]=965726722;
f[18][17]=714247039;
f[18][18]=863172746;
f[19][1]=21892;
f[19][2]=45239074;
f[19][3]=783414796;
f[19][4]=66436362;
f[19][5]=482820599;
f[19][6]=11408306;
f[19][7]=282700546;
f[19][8]=21286596;
f[19][9]=260816893;
f[19][10]=296728524;
f[19][11]=271275558;
f[19][12]=162854127;
f[19][13]=528839023;
f[19][14]=588438252;
f[19][15]=941608571;
f[19][16]=338429562;
f[19][17]=618120378;
f[19][18]=848394410;
f[19][19]=401063754;
f[20][1]=35422;
f[20][2]=109216786;
f[20][3]=825887878;
f[20][4]=846744451;
f[20][5]=554824385;
f[20][6]=408647554;
f[20][7]=22756408;
f[20][8]=938070641;
f[20][9]=439097719;
f[20][10]=376322515;
f[20][11]=799381749;
f[20][12]=119197299;
f[20][13]=685787560;
f[20][14]=129037699;
f[20][15]=451194912;
f[20][16]=576341965;
f[20][17]=406755252;
f[20][18]=918564227;
f[20][19]=94291214;
f[20][20]=758010071;
f[21][1]=57314;
f[21][2]=263672646;
f[21][3]=657842797;
f[21][4]=425986066;
f[21][5]=275449685;
f[21][6]=583029172;
f[21][7]=718867329;
f[21][8]=203346338;
f[21][9]=65628471;
f[21][10]=829240861;
f[21][11]=672484501;
f[21][12]=853627597;
f[21][13]=880266714;
f[21][14]=601970693;
f[21][15]=874206699;
f[21][16]=713291657;
f[21][17]=873096218;
f[21][18]=972683633;
f[21][19]=917665023;
f[21][20]=226060160;
f[21][21]=405975872;
f[22][1]=92736;
f[22][2]=636562078;
f[22][3]=671733974;
f[22][4]=373151395;
f[22][5]=689665743;
f[22][6]=578960700;
f[22][7]=481594643;
f[22][8]=355116018;
f[22][9]=704122152;
f[22][10]=345163478;
f[22][11]=732547187;
f[22][12]=839683838;
f[22][13]=864236269;
f[22][14]=687132429;
f[22][15]=756332430;
f[22][16]=598042173;
f[22][17]=978969827;
f[22][18]=483708092;
f[22][19]=157350705;
f[22][20]=233192420;
f[22][21]=654514971;
f[22][22]=52283765;
f[23][1]=150050;
f[23][2]=538552449;
f[23][3]=514132522;
f[23][4]=182691803;
f[23][5]=130244776;
f[23][6]=657025630;
f[23][7]=880467361;
f[23][8]=975112953;
f[23][9]=562810749;
f[23][10]=264627553;
f[23][11]=739859028;
f[23][12]=160099438;
f[23][13]=375095868;
f[23][14]=688899553;
f[23][15]=2727357;
f[23][16]=369214419;
f[23][17]=751833966;
f[23][18]=731653021;
f[23][19]=961444462;
f[23][20]=517163752;
f[23][21]=621055919;
f[23][22]=582044100;
f[23][23]=470224525;
f[24][1]=242786;
f[24][2]=715422623;
f[24][3]=239803598;
f[24][4]=635146701;
f[24][5]=84517320;
f[24][6]=749395312;
f[24][7]=6231573;
f[24][8]=378154791;
f[24][9]=48280463;
f[24][10]=262980650;
f[24][11]=816324661;
f[24][12]=892558209;
f[24][13]=822629042;
f[24][14]=897976323;
f[24][15]=579196025;
f[24][16]=118063594;
f[24][17]=14117233;
f[24][18]=873733338;
f[24][19]=110126488;
f[24][20]=43469418;
f[24][21]=429295212;
f[24][22]=367195929;
f[24][23]=287282346;
f[24][24]=833181761;
cout<<f[n][m];
return 0;
}
/*
Hello!!
Sample:
----------------
*/
\(\text{Summary}\)
后劲不足,前两个小时之后都是垃圾时间。
当然可能是题目难度 gap 相对较大,同时后半部分个人思维状态太拉了,脑子变成一团浆糊了。
因为 \(\text{G}\) 确实有一些细节需要处理,可能得想清楚再下手,另外如果中间卡住了,需要注意是否将问题转化到了最易于处理的形式,而非对着一个性质不那么优的结构下手。
浙公网安备 33010602011771号