2021.07.10【NOIP提高B组】模拟 总结

2021.07.10【NOIP提高B组】模拟 总结

第一题:设 f i f_i fi表示前 i i i此操作每个位置不在原来位置的概率(因为每一个位置的概率是相同的)。转移考虑上一个位置是否相同并转移。

公式:
f i = f i − 1 ( 1 − 1 C n 2 ) + ( 1 − f i − 1 ) n − 1 C n 2 f_i=f_{i-1}(1-\frac{1}{C_n^2})+(1-f_{i-1})\frac{n-1}{C_n^2} fi=fi1(1Cn21)+(1fi1)Cn2n1
答案:
a n s = ∑ ( 1 − f k ) a i × i ( n − i + 1 ) C n + 1 2 + f k s u m − a i n − 1 × i ( n − i + 1 ) C n + 1 2 ans=\sum(1-f_k)a_i\times\frac{i(n-i+1)}{C_{n+1}^2}+f_k\frac{sum-a_i}{n-1}\times\frac{i(n-i+1)}{C_{n+1}^2} ans=(1fk)ai×Cn+12i(ni+1)+fkn1sumai×Cn+12i(ni+1)
第二题:如果一个点在基环树的树上(不包括环上的点),那么它的方案一定时 k − 1 k-1 k1,因为它只有一个父亲约束它。如果在环上,有一个动态规划:设 f i , 0 / 1 f_{i,0/1} fi,0/1表示第 i i i个点与第 1 1 1个点相同或不相同的方案数。

转移:
f i , 0 = f i − 1 , 1 f i , 1 = f i − 1 , 0 × ( k − 1 ) + f i − 1 , 1 × ( k − 2 ) f_{i,0}=f_{i-1,1}\\ f_{i,1}=f_{i-1,0}\times (k-1)+f_{i-1,1}\times (k-2) fi,0=fi1,1fi,1=fi1,0×(k1)+fi1,1×(k2)

接着看一下每一个基环树的答案乘起来即可。

第三题:一眼看时分数规划,发现不会做。

二分 x x x,答案要求 ∑ n 1 q 1 i + ∑ n 2 q 2 i ∑ n 1 c 1 i + ∑ n 2 c 2 i \frac{\sum^{n1}{q1_i}+\sum^{n2}{q2i}}{\sum^{n1}{c1_i}+\sum^{n2}{c2i}} n1c1i+n2c2in1q1i+n2q2i最大。
∑ n 1 q 1 i + ∑ n 2 q 2 i ∑ n 1 c 1 i + ∑ n 2 c 2 i ≥ x ∑ n 1 q 1 i − x c 1 i + ∑ n 2 q 2 i − x c 2 i ≥ 0 \frac{\sum^{n1}{q1_i}+\sum^{n2}{q2i}}{\sum^{n1}{c1_i}+\sum^{n2}{c2i}}\ge x\\ \sum^{n1}{q1_i-xc1_i}+\sum^{n2}{q2_i-xc2_i}\ge 0 n1c1i+n2c2in1q1i+n2q2ixn1q1ixc1i+n2q2ixc2i0
发现按 q 1 i − x c 1 i − ( q 2 i − x c 2 i ) q1_i-xc1_i-(q2_i-xc2_i) q1ixc1i(q2ixc2i)从大到小排序,中间一定会有一个分界线:前面的时 1 1 1队的,后面的时 2 2 2队的。

f i , j f_{i,j} fi,j表示前 i i i队选了 j j j 1 1 1队的答案, g g g同理(选 2 2 2)。枚举分界线就行了。

第四题:首先看一下小于 k k k的答案怎么求,发现 C n k C_n^k Cnk很小,所以直接暴力求,设为 y y y。那么我们可以用一种方法把所有的答案算出来,设为 x x x。首先把序列分成两部分分别算出 ∑ a i − b i \sum a_i-b_i aibi ∑ a i − c i \sum a_i-c_i aici。前后的答案分别设为 f , g f,g f,g。则我们要保证 f ( ∑ a i − b i ) + g ( ∑ a i − b i ) > 0 , f ( ∑ a i − c i ) + g ( ∑ a i − c i ) > 0 f(\sum a_i-b_i)+g(\sum a_i-b_i)>0,f(\sum a_i-c_i)+g(\sum a_i-c_i)>0 f(aibi)+g(aibi)>0,f(aici)+g(aici)>0

g g g取个相反数,就变成了二维偏序。考虑树状数组维护:首先离散化一个,然后把另一个排序,双指针维护,用星星点灯的做法搞一下即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[50],b[50],c[50],n,k,m1,m2;
struct node{ll s1,s2;}f[150000],g[150000];
struct node2{ll val,rk,id;}a1[150000],a2[150000];
const ll inf=1000000000000000000;
void dfs1(ll x,ll en,ll st,ll sum1,ll sum2){
	m1=max(m1,st);
	if (x>en){
		f[st].s1=sum1;
		f[st].s2=sum2;
		return;
	}
	dfs1(x+1,en,st<<1,sum1,sum2);
	dfs1(x+1,en,st<<1|1,sum1+a[x]-b[x],sum2+a[x]-c[x]);
}
void dfs2(ll x,ll en,ll st,ll sum1,ll sum2){
	m2=max(m2,st);
	if (x>en){
		g[st].s1=sum1;
		g[st].s2=sum2;
		return;
	}
	dfs2(x+1,en,st<<1,sum1,sum2);
	dfs2(x+1,en,st<<1|1,sum1+a[x]-b[x],sum2+a[x]-c[x]);
}
ll bz[50];
ll ans2=0; 
void dfs3(ll x,ll las,ll en,ll sum1,ll sum2){
	if (x>en){
		if (sum1>0&&sum2>0)ans2++;
		return;
	}
	for (ll i=las+1;i<=n;i++)
		if (!bz[i]){
			bz[i]=1;
			dfs3(x+1,i,en,sum1+a[i]-b[i],sum2+a[i]-c[i]);
			bz[i]=0; 
		}
} 
bool cmp(node2 x,node2 y){return x.val<y.val;}
bool cmp2(node x,node y){return x.s2<y.s2;}
ll tr[300000],m;
ll lowbit(ll x){return x&(-x);}
void add(ll x,ll v){for (ll i=x;i<=m;i+=lowbit(i))tr[i]+=v;}
ll query(ll x){ll sum=0;for (ll i=x;i;i-=lowbit(i))sum+=tr[i];return sum;}
int main(){
	freopen("show.in","r",stdin);
	freopen("show.out","w",stdout);
	scanf("%lld%lld",&n,&k);
	for (ll i=1;i<=n;i++)scanf("%lld",&a[i]); 
	for (ll i=1;i<=n;i++)scanf("%lld",&b[i]); 
	for (ll i=1;i<=n;i++)scanf("%lld",&c[i]); 
	dfs1(1,n/2,0,0,0);
	dfs2(n/2+1,n,0,0,0);
	ll ans=0;
	for (ll i=0;i<=m2;i++)g[i].s1=-g[i].s1,g[i].s2=-g[i].s2;
	for (ll i=m1+1;i;i--)f[i].s1=f[i-1].s1,f[i].s2=f[i-1].s2;m1++;
	for (ll i=m2+1;i;i--)g[i].s1=g[i-1].s1,g[i].s2=g[i-1].s2;m2++;
	for (ll i=1;i<=m1;i++)a1[i].val=f[i].s1,a1[i].id=i;
	for (ll i=1;i<=m2;i++)a1[i+m1].val=g[i].s1,a1[i+m1].id=i+m1;
	sort(a1+1,a1+m1+m2+1,cmp);
	a1[0].val=-inf;
	for (ll i=1;i<=m1+m2;i++)a1[i].rk=a1[i-1].rk+(a1[i].val==a1[i-1].val?0:1);m=a1[m1+m2].rk;
	for (ll i=1;i<=m1+m2;i++)
		if (a1[i].id>m1)g[a1[i].id-m1].s1=a1[i].rk;
		else f[a1[i].id].s1=a1[i].rk;
	sort(f+1,f+m1+1,cmp2),sort(g+1,g+m2+1,cmp2);
	for (ll i=1;i<=m1;i++)add(f[i].s1,1);
	ll j=1;
	for (ll i=1;i<=m2;i++){
		while (g[i].s2>=f[j].s2&&j<=m1)add(f[j].s1,-1),j++;
		if (j>m1)break;
		ans+=m1-j+1-query(g[i].s1);
	}
	for (ll i=1;i<k;i++)memset(bz,0,sizeof(bz)),dfs3(1,0,i,0,0);
	printf("%lld\n",ans-ans2);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值