O M A Z E 杂赛整理

THUCP 2026 初赛

A. Asian Soul

赛时思路是,考虑重链剖分,将询问剖成 \(O(\log n)\) 条重链的前缀。对于一条重链的前缀,ban 掉某个轻子树的询问,可以离线下来从头逐一加入轻子树,然后一边删除一边回答。由于一个点只会在 \(O(\log n)\) 条重链上出现,总增删次数就是 \(O(n\log n)\) 的,用线段树处理就是 \(O(n\log^2 n)\) 的。

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
const int N=5e5+9;

vector<int> e[N],pos[N];
int a[N],ql[N],qr[N],qu[N],n,m,q;

int fa[N],siz[N],dep[N],hson[N];
inline void GetHSon(int x){
    siz[x]=1;
    for(int y:e[x]){
        if(y==fa[x]) continue ;
        fa[y]=x;
        dep[y]=dep[x]+1;
        GetHSon(y);
        siz[x]+=siz[y];
        if(!hson[x]||siz[hson[x]]<siz[y]) hson[x]=y;
    }
}
int dfn[N],idfn[N],top[N],dcnt;
inline void GetTop(int x,int t){
    top[x]=t;
    dfn[x]=++dcnt;
    idfn[dcnt]=x;
    if(hson[x]) GetTop(hson[x],t);
    for(int y:e[x]){
        if(y==fa[x]) continue ;
        if(y==hson[x]) continue ;
        GetTop(y,y);
    }
}

vector<array<int,2>> qry[N];
inline void InsQ(int x,int id){
    int lst=0;
    while(x){
        qry[x].push_back({lst,id});
        lst=top[x];
        x=fa[top[x]];
    }
}

struct Node{
    int l,r,dat;
}tr[N<<2];

inline void PushUp(int x){tr[x].dat=max(tr[x<<1].dat,tr[x<<1|1].dat);}
inline void Build(int x,int l,int r){
    tr[x].l=l,tr[x].r=r;
    if(tr[x].l==tr[x].r) return tr[x].dat=0,void();
    int mid=tr[x].l+tr[x].r>>1;
    Build(x<<1,l,mid),Build(x<<1|1,mid+1,r);
    PushUp(x);
}
inline void Set(int x,int pos,int k){
    if(tr[x].l==tr[x].r) return tr[x].dat=k,void();
    int mid=tr[x].l+tr[x].r>>1;
    if(pos<=mid) Set(x<<1,pos,k);
    else Set(x<<1|1,pos,k);
    PushUp(x);
}
inline int Query(int x,int l,int r){
    if(l<=tr[x].l&&tr[x].r<=r) return tr[x].dat;
    int mid=tr[x].l+tr[x].r>>1;
    if(r<=mid) return Query(x<<1,l,r);
    else if(l>mid) return Query(x<<1|1,l,r);
    else return max(Query(x<<1,l,mid),Query(x<<1|1,mid+1,r));
}

int ans[N];
vector<int> tmp[N];
inline void Calc(){
    auto Ins=[](int x,int k){for(int i:pos[x]) Set(1,i,k);};
    auto Ers=[](int x){for(int i:pos[x]) Set(1,i,0);};
    for(int x=1;x<=n;x++){
        if(x!=top[x]) continue ;
        int low=0;
        for(int y=x;y;y=hson[y]){
            Ins(y,y);
            for(int z:e[y]){
                if(z==fa[y]) continue ;
                if(z==hson[y]) continue ;
                for(int i=dfn[z];i<dfn[z]+siz[z];i++) Ins(idfn[i],y);
            }
            for(auto p:qry[y]) tmp[p[0]].push_back(p[1]);
            for(int i:tmp[0]) ans[i]=max(ans[i],Query(1,ql[i],qr[i]));
            tmp[0].clear();
            for(int z:e[y]){
                if(z==fa[y]) continue ;
                if(z==hson[y]) continue ;
                for(int i=dfn[z];i<dfn[z]+siz[z];i++) Ers(idfn[i]);
                for(int i:tmp[z]) ans[i]=max(ans[i],Query(1,ql[i],qr[i]));
                for(int i=dfn[z];i<dfn[z]+siz[z];i++) Ins(idfn[i],y);
                tmp[z].clear();
            }
        }
        for(int y=x;y;y=hson[y]){
            Ers(y);
            for(int z:e[y]){
                if(z==fa[y]) continue ;
                if(z==hson[y]) continue ;
                for(int i=dfn[z];i<dfn[z]+siz[z];i++) Ers(idfn[i]);
            }
            low=y;
        }
        for(int y=low;y;y=fa[y]){
            for(auto p:qry[y]){
                int i=p[1];
                if(Query(1,ql[i],qr[i])) ans[i]=max(ans[i],y);
            }
            Ins(y,1);
            for(int z:e[y]){
                if(z==fa[y]) continue ;
                if(z==hson[y]) continue ;
                for(int i=dfn[z];i<dfn[z]+siz[z];i++) Ins(idfn[i],1);
            }
            if(y==x) break ;
        }
        for(int y=x;y;y=hson[y]){
            Ers(y);
            for(int z:e[y]){
                if(z==fa[y]) continue ;
                if(z==hson[y]) continue ;
                for(int i=dfn[z];i<dfn[z]+siz[z];i++) Ers(idfn[i]);
            }
        }
    }
}

signed main(){
    cin.tie(0),cout.tie(0);
    ios::sync_with_stdio(0);

    cin>>n>>m>>q;
    for(int i=1,u,v;i<n;i++){
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=m;i++) cin>>a[i],pos[a[i]].push_back(i);
    for(int i=1;i<=q;i++) cin>>ql[i]>>qr[i]>>qu[i];

    GetHSon(1),GetTop(1,1);
    for(int i=1;i<=q;i++) InsQ(qu[i],i);
    Build(1,1,m);
    Calc();

    for(int i=1;i<=q;i++) cout<<ans[i]<<endl;

    return 0;
}

正解考虑把询问摊到线段树的 \(O(n\log n)\) 的区间上。对于每个线段树节点,把区间内的节点和询问节点共同的虚树建出来,把树遍历一遍就可以得到答案,使用归并和另类虚树建法就是 \(O(n\log n)\)

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
const int N=5e5+9;
const int lgN=2e1;

vector<int> e[N];
int a[N],ql[N],qr[N],qu[N],n,m,q;

vector<int> qry[N<<2];
inline void Insert(int x,int L,int R,int l,int r,int id){
	if(l<=L&&R<=r) return qry[x].push_back(id);
	int mid=L+R>>1;
	if(l<=mid) Insert(x<<1,L,mid,l,r,id);
	if(r>mid) Insert(x<<1|1,mid+1,R,l,r,id);
}

int fa[N],elr[N<<1],pos[N],ecnt;
inline void GetElr(int x){
	elr[++ecnt]=x;
	pos[x]=ecnt;
	for(int y:e[x]){
		if(y==fa[x]) continue ;
		fa[y]=x;
		GetElr(y);
		elr[++ecnt]=x;
	}
}
int mn[lgN][N<<1],lg[N<<1];
inline void InitLCA(){
	for(int i=2;i<=ecnt;i++) lg[i]=lg[i>>1]+1;
	for(int i=1;i<=ecnt;i++) mn[0][i]=pos[elr[i]];
	for(int k=1;k<=lg[ecnt];k++){
		for(int i=1;i+(1<<k)-1<=ecnt;i++){
			mn[k][i]=min(mn[k-1][i],mn[k-1][i+(1<<k-1)]);
		}
	}
}
inline int LCA(int x,int y){
	x=pos[x],y=pos[y];
	if(x>y) swap(x,y);
	int k=lg[y-x+1];
	return elr[min(mn[k][x],mn[k][y-(1<<k)+1])];
}

vector<int> ve[N];
inline int GetVir(vector<int> v,vector<int> &node){
	vector<int> stk;
	for(int x:v){
		if(stk.size()){
			int lca=LCA(stk.back(),x);
			if(stk.back()!=lca){
				int lst=0;
				while(stk.size()&&pos[stk.back()]>pos[lca]){
					if(lst) ve[stk.back()].push_back(lst);
					lst=stk.back();
					stk.pop_back();
				}
				if(stk.back()!=lca){
					stk.push_back(lca);
					node.push_back(lca);
				}
				ve[lca].push_back(lst);
			}
		}
		stk.push_back(x);
		node.push_back(x);
	}
	for(int i=0;i+1<stk.size();i++) ve[stk[i]].push_back(stk[i+1]);
	return stk.front();
}

int imp[N],vsiz[N],vson[N],f[N];
inline void GetVSiz(int x){
	vsiz[x]=imp[x];
	for(int y:ve[x]){
		GetVSiz(y);
		vsiz[x]+=vsiz[y];
		vson[x]+=bool(vsiz[y]);
	}
	vson[x]+=imp[x];
}
inline void GetF(int x,int k){
	f[x]=vson[x]?max(x,k):k;
	for(int y:ve[x]) GetF(y,vson[x]-bool(vsiz[y])?max(x,k):k);
}

int ans[N];
inline void Merge(vector<int> &p,vector<int> &q,vector<int> &r){
	int i=0,j=0;
	while(i<p.size()&&j<q.size()){
		if(pos[p[i]]<pos[q[j]]) r.push_back(p[i++]);
		else r.push_back(q[j++]);
	}
	while(i<p.size()) r.push_back(p[i++]);
	while(j<q.size()) r.push_back(q[j++]);
	r.erase(unique(r.begin(),r.end()),r.end());
}
vector<int> v[N<<2];
inline void Solve(int x,int L,int R){
	vector<int> vq,rl,node;
	if(L!=R){
		int mid=L+R>>1;
		Solve(x<<1,L,mid);
		Solve(x<<1|1,mid+1,R);
		Merge(v[x<<1],v[x<<1|1],v[x]);
	}else v[x]={a[L]};
	for(int i=L;i<=R;i++) imp[a[i]]=1;
	for(int i:qry[x]) vq.push_back(qu[i]);
	Merge(v[x],vq,rl);
	int root=GetVir(rl,node);
	GetVSiz(root);
	GetF(root,0);
	for(int i:qry[x]) ans[i]=max(ans[i],f[qu[i]]);
	for(int i:node) imp[i]=vsiz[i]=vson[i]=f[i]=0,ve[i].clear();
}

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	
	cin>>n>>m>>q;
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		e[u].push_back(v);
		e[v].push_back(u);
	}
	for(int i=1;i<=m;i++) cin>>a[i];
	for(int i=1;i<=q;i++) cin>>ql[i]>>qr[i]>>qu[i];

	GetElr(1),InitLCA();
	vector<int> p(q);
	iota(p.begin(),p.end(),1);
	sort(p.begin(),p.end(),[](int i,int j){return pos[qu[i]]<pos[qu[j]];});
	for(int i:p) Insert(1,1,m,ql[i],qr[i],i);
	Solve(1,1,m);

	for(int i=1;i<=q;i++) cout<<ans[i]<<endl;

	return 0;
}

B. 回响形态

考虑把原来的串 \(s\) 反转过来,令其为 \(t\)。那么串 \(s_it_{2k-i}\ldots s_js_{2k-j}\) 是回文串等价于 \(s[i:j]=s[2k-j,2k-i]\)

因此直接 Manacher 对此类回文串计数即可,时间复杂度 \(O(nq)\)

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
using ll=long long;
const int N=1e6+9;

int f[N<<1],n,q;
char s[N],t[N],o[N<<1];

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>s[i];

	while(q--){
		int k;
		cin>>k;
		for(int i=1;i<=n;i++) t[i]='#';
		for(int i=max(1,k-n);i<=min(n,k-1);i++) t[i]=s[k-i];
		for(int i=1;i<=2*n;i++) o[i]=i&1?s[i+1>>1]:t[i+1>>1];
		
		ll ans=0;
		for(int i=1,l=0,r=-1;i<k;i++){
			int k=i>r?0:min(f[l+r-i-1],r-i);
			while(i-k>=1&&i+k+1<=2*n&&o[i-k]==o[i+k+1]) k++;
			f[i]=k--;
			if(i+k+1>r) l=i-k,r=i+k+1;
			ans+=f[i]+(i&1)>>1;
		}

		cout<<ans<<endl;
	}

	return 0;
}

F. 庭中有奇树

BFS 序在子树中只有树高个区间。

因此考虑先记录所有会用到的查询区间,离散化之后只有至多只有 \(O(\sqrt[2^d]V+qd)\) 个节点,\(d=2\) 取到 \(O(\sqrt[4]V+q)\)

修改考虑记录每个节点管辖区间按位与的结果,修改之后区间内有值会变就暴力递归修改,查询直接逐一对每个区间查询即可。

均摊分析之后是 \(O(n\log n\log V)\) 的。

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
using ull=unsigned long long;
using bint=__int128;
const int T=4.5e6+9;
const int N=1e6+9;

ull qx[N],qc[N],n;
int op[N],q,tot;

vector<ull> pos;

struct Node{
	ull len,dat,com;
}tr[T<<2];

inline void PushUp(int x){
	tr[x].dat=tr[x<<1].dat^tr[x<<1|1].dat;
	tr[x].com=tr[x<<1].com&tr[x<<1|1].com;
}
inline void Build(int x,int l,int r){
	if(l==r) return tr[x].len=pos[r+1]-pos[l],void();
	int mid=l+r>>1;
	Build(x<<1,l,mid),Build(x<<1|1,mid+1,r);
	PushUp(x);
}
inline void Modify(int x,int L,int R,int l,int r,ull k){
	if((tr[x].com&k)==k) return ;
	if(L==R){
		tr[x].com|=k;
		tr[x].dat=tr[x].len&1?tr[x].com:0;
		return ;
	}
	int mid=L+R>>1;
	if(l<=mid) Modify(x<<1,L,mid,l,r,k);
	if(r>mid) Modify(x<<1|1,mid+1,R,l,r,k);
	PushUp(x);
}
inline ull Query(int x,int L,int R,int l,int r){
	if(l<=L&&R<=r) return tr[x].dat;
	int mid=L+R>>1;
	if(r<=mid) return Query(x<<1,L,mid,l,r);
	else if(l>mid) return Query(x<<1|1,mid+1,R,l,r);
	else return Query(x<<1,L,mid,l,r)^Query(x<<1|1,mid+1,R,l,r);
}

inline bint L(bint l){return l*(l-1)/2+2;}
inline bint R(bint r){return L(r+1)-1;}
inline void Insert(bint l,bint r){
	pos.push_back(l);
	pos.push_back(r+1);
	l=L(l),r=R(r);
	if(l>n) return ;
	r=min(r,bint(n));
	Insert(l,r);
}
inline void Mod(bint l,bint r,ull k){
	int lp=lower_bound(pos.begin(),pos.end(),ull(l))-pos.begin();
	int rp=upper_bound(pos.begin(),pos.end(),ull(r))-pos.begin()-1;
	Modify(1,1,tot,lp,rp,k);
	l=L(l),r=R(r);
	if(l>n) return ;
	r=min(r,bint(n));
	Mod(l,r,k);
}
inline ull Qry(bint l,bint r){
	int lp=lower_bound(pos.begin(),pos.end(),ull(l))-pos.begin();
	int rp=upper_bound(pos.begin(),pos.end(),ull(r))-pos.begin()-1;
	ull res=Query(1,1,tot,lp,rp);
	l=L(l),r=R(r);
	if(l>n) return res;
	r=min(r,bint(n));
	return res^Qry(l,r);
}

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	cin>>n>>q;
	for(int i=1;i<=q;i++){
		cin>>op[i];
		if(op[i]==1) cin>>qx[i]>>qc[i];
		else cin>>qx[i];
		Insert(qx[i],qx[i]);
	}
	
	pos.push_back(0),pos.push_back(n+1);
	sort(pos.begin(),pos.end());
	pos.erase(unique(pos.begin(),pos.end()),pos.end());

	tot=pos.size()-1;
	Build(1,1,tot);

	for(int i=1;i<=q;i++){
		if(op[i]==1) Mod(qx[i],qx[i],qc[i]);
		else cout<<Qry(qx[i],qx[i])<<endl;
	}

	return 0;
}

J. 序列

不知道为什么但是 98 分钟没过题了好急啊瞎几把猜个结论试试不然爆了欸怎么过了。

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
using ll=long long;

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	int T;
	cin>>T;
	while(T--){
		ll n,m;
		cin>>n>>m;
		if(~n&1) cout<<"NO"<<endl;
		else{
			ll cnt=0,x=m;
			while(true){
				ll y=1ull<<__lg(x)+1;
				y-=x;
				if(x==y) break ;
				cnt++,x=y;
			}
			int k=__lg(x)+1;
			if(~k&1) cout<<"NO"<<endl;
			else if(cnt*2+1>n) cout<<"NO"<<endl;
			else cout<<"YES"<<endl;
		}
	}

	return 0;
}

NERC 2025

A. Alphabet City

对每种字母统计个数即可。

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
using ll=long long;
const int N=5e5+9;

int c[N][26],tot[26],n,m;
string s[N];

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>s[i];

	for(int i=1;i<=n;i++){
		for(auto t:s[i]){
			c[i][t-'A']++;
			tot[t-'A']++;
		}
	}

	for(int i=1;i<=n;i++){
		ll tmp[26],res=LLONG_MAX,err=0;
		for(int j=0;j<26;j++){
			tmp[j]=1ll*m*(tot[j]-c[i][j])-c[i][j];
			if(tot[j]-c[i][j]) res=min(res,tmp[j]/(tot[j]-c[i][j]));
			err|=(tmp[j]<0);
		}
		if(err) cout<<-1<<' ';
		else cout<<res<<' ';
	}

	cout<<endl;

	return 0;
}

B. Battle of Arrays

不是我都猜对结论了怎么是假题啊。

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'

inline void Solve(){
	int n,m;
	cin>>n>>m;
	vector<int> a(n),b(m);
	for(int &x:a) cin>>x;
	for(int &x:b) cin>>x;

	priority_queue<int> q[2];
	for(int x:a) q[0].push(x);
	for(int x:b) q[1].push(x);

	for(int o=0;q[0].size()&&q[1].size();o^=1){
		int x=q[o^1].top()-q[o].top();
		q[o^1].pop();
		if(x>0) q[o^1].push(x);
	}

	if(!q[0].size()) cout<<"Bob"<<endl;
	else cout<<"Alice"<<endl;
}

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	int T;
	cin>>T;
	while(T--) Solve();

	return 0;
}

D. Doorway

显然每个门要么滑倒最左边要么滑倒最右边,枚举区间并的左端点,堆维护即可。

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
const int N=3e5+9;

int k[N],lx[N],rx[N],lp[N],rp[N],it[N],s[N],n;
vector<int> len[N];
multiset<int> ls,rs;

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>k[i]>>lx[i]>>rx[i];
		len[i].resize(k[i]);
		for(int &x:len[i]) cin>>x;
		s[i]=accumulate(len[i].begin(),len[i].end(),0);
	}

	int ans=0;
	priority_queue<array<int,2>> q;
	for(int i=1;i<=n;i++){
		ls.insert(lp[i]=lx[i]);
		rs.insert(rp[i]=rx[i]-s[i]);
		it[i]=0;
		if(it[i]<k[i]) q.push({-(lp[i]+len[i][it[i]]),i});
	}

	ans=max(ans,*rs.begin()-*ls.rbegin());
	while(q.size()){
		int i=q.top()[1];
		q.pop();
		ls.erase(ls.find(lp[i]));
		rs.erase(rs.find(rp[i]));
		ls.insert(lp[i]+=len[i][it[i]]);
		rs.insert(rp[i]+=len[i][it[i]]);
		it[i]++;
		if(it[i]<k[i]) q.push({-(lp[i]+len[i][it[i]]),i});
		ans=max(ans,*rs.begin()-*ls.rbegin());
	}

	cout<<ans<<endl;

	return 0;
}

G. Greta's Game

考虑求解每个位置操作(即令 \(a_i,a_{i+1}\) 加一)的次数 \(x_i\),有限制 \(x_i+x_{i-1}=a_i\)

那么奇数就可以直接解出 \(x_i\),然后答案是 \(\displaystyle \max_{i=1}^n x_i\)\(\displaystyle \lceil \dfrac{\sum_{i=1}^nx_i}{n-1}\rceil\) 的较大值。

偶数由于 \(\displaystyle \lceil \dfrac{\sum_{i=1}^nx_i}{n-1}\rceil\) 总是固定,相当于要最小化 \(\displaystyle \max_{i=1}^n x_i\)。令 \(x_1\) 为主元,那么 \(x_i\)\(x_1\) 的关系无非就是一条斜率要么是 \(1\) 要么是 \(-1\) 的直线,求出合法区间内上包络线的最小值即为 \(\displaystyle \min_x\max_{i=1}^n x_i\)

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
using ll=long long;
const int N=5e5+9;

int a[N],x[N],n;
inline bool Check(int k){
	ll sum=0;
	for(int i=1;i<=n;i++){
		if(x[i]>k) return 0;
		sum+=k-x[i];
	}
	return sum>=k;
}
inline int T(){
	int l=-1,r=1e9+7;
	while(l+1<r){
		int mid=l+r>>1;
		if(Check(mid)) r=mid;
		else l=mid;
	}
	return r;
}

inline void Solve(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];

	if(n&1){
		ll sum=0;
		for(int i=2;i<=n;i++){
			if(~i&1) sum+=a[i];
			else sum-=a[i];
		}
		sum+=a[1];
		x[1]=sum>>1;
		for(int i=2;i<=n;i++) x[i]=a[i]-x[i-1];
	}else{
		ll bp=0,bn=-1e18,l=0,r=1e18,c=0;
		for(int i=2;i<=n;i++){
			if(~i&1) c+=a[i];
			else c-=a[i];
			if(~i&1){
				bn=max(bn,c);
				r=min(r,c);
			}else{
				bp=max(bp,-c);
				l=max(l,c);
			}
		}
		x[1]=min(max(bn-bp>>1,l),r);
		for(int i=2;i<=n;i++) x[i]=a[i]-x[i-1];
	}

	cout<<T()<<endl;
}

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	int T;
	cin>>T;
	while(T--) Solve();

	return 0;
}

J. Jinx or Jackpot

\(a/b\) 表示 \(b\) 局中胜了 \(a\) 局,设 \(P(a,b)\) 表示 \(a/b\) 的情况下 \((a+1)/(b+1)\) 的概率。

那么 \(\displaystyle P(a,b)=P((a+1)/(b+1)|a/b)=\dfrac {\sum_{i=1}^np_i^{a+1}(1-p_i)^{b-a}}{\sum_{i=1}^np_i^a(1-p_i)^{b-a}}\)

随便手玩一下发现要么 All in 要么远离赌博,设 \(F(a,b)\) 表示目前 \(a/b\),继续操作下去最多可以翻 \(F(a,b)\) 倍。

那么 \(F(a,b)=\max(P(a,b)F(a+1,b+1)+(1-P(a,b))F(a,b+1),2P(a,b)F(a+1,b+1))\)

答案就是 \(10^3(F(0,0)-1)\),时间复杂度依实现为 \(O(n+Ck^2)\)\(O(nk^2)\),其中 \(C=100\)

#include<bits/stdc++.h>

using namespace std;

#define endl '\n'
using ld=long double;
const int N=1e5+9;
const int K=3e1+9;
const ld eps=1e-12;

int p[N],n,k;
ld pw[N][K],qw[N][K],P[K][K],F[K][K];

signed main(){
	cin.tie(0),cout.tie(0);
	ios::sync_with_stdio(0);

	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>p[i];

	for(int i=1;i<=n;i++){
		const ld t=p[i]/ld(100);
		pw[i][0]=qw[i][0]=1;
		for(int j=1;j<=k+1;j++){
			pw[i][j]=pw[i][j-1]*t;
			qw[i][j]=qw[i][j-1]*(1-t);
		}
	}

	for(int i=0;i<=k;i++){
		for(int j=i;j<=k;j++){
			ld f=0,g=eps;
			for(int o=1;o<=n;o++) f+=pw[o][i+1]*qw[o][j-i];
			for(int o=1;o<=n;o++) g+=pw[o][i]*qw[o][j-i];
			P[i][j]=f/g;
		}
	}
	for(int i=0;i<=k;i++) F[i][k]=1;
	for(int j=k-1;j>=0;j--){
		for(int i=0;i<=j;i++){
			F[i][j]=max(P[i][j]*F[i+1][j+1]+(1-P[i][j])*F[i][j+1],2*P[i][j]*F[i+1][j+1]);
		}
	}

	cout<<fixed<<setprecision(10)<<1000*(F[0][0]-1)<<endl;

	return 0;
}
posted @ 2025-12-20 17:08  JoeyJiang  阅读(8)  评论(0)    收藏  举报