NOIP2011提高组复赛day2解析

发布时间 2023-08-31 23:15:00作者: 天雷小兔

1.计算系数

题目:https://www.luogu.com.cn/problem/P1313

 解析:

直接套用二项式定理,使用快速幂计算组合数

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3+39+7,mod = 1e4+7;
ll fac[N],a,b,k,n,m; 
void init(){
	fac[0]=1;
	for(int i=1;i<=1000;i++)fac[i]=(fac[i-1]*i)%mod;
}
ll quickPow(ll a,ll b,ll m){
	ll ans=1;
	while(b){
		if(b&1)ans=((ans%m)*(a%m))%m;
		a=((a%m)*(a%m))%m;
		b>>=1;
	}
	return ans;
}
ll inv(ll a,ll m){
	return quickPow(a,m-2,m);
}
int main(){
//	freopen("factor.in","r",stdin);
//	freopen("factor.out","w",stdout); 
	
	init(); 
	cin>>a>>b>>k>>n>>m;
	
	if(k<=1)cout<<1;
	else cout<<fac[k]%mod*quickPow(a,n,mod)%mod*inv(fac[n],mod)%mod*quickPow(b,m,mod)%mod*inv(fac[m],mod)%mod;
	
	return 0;
}

  

2.聪明的质监员

题目:https://www.luogu.com.cn/problem/P1314

解析:

使用二分枚举W,每次预处理前缀和,使用O(m)的复杂度进行验证

坑点:

二分的条件非常重要,正确的二分应该比较验证得到的结果与S比较,进行二分

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5+39+7;
ll n,m,S,ans=1e18,maxW=0,w[N],v[N],L[N],R[N],sum[N],cnt[N];
ll calc(ll W){
	sum[0]=cnt[0]=0;
	for(int i=1;i<=n;i++){
		sum[i]=sum[i-1]+(w[i]>=W?v[i]:0);
		cnt[i]=cnt[i-1]+(w[i]>=W?1:0);
	}
	
	ll num=0;
	for(int i=1;i<=m;i++)num+=(cnt[R[i]]-cnt[L[i]-1])*(sum[R[i]]-sum[L[i]-1]);
	
	return num;
} 
int main(){
//	freopen("qc.in","r",stdin);
//	freopen("qc.out","w",stdout);
	cin>>n>>m>>S;
	for(int i=1;i<=n;i++){
		cin>>w[i]>>v[i];
		maxW=max(maxW,w[i]);
	}
	for(int i=1;i<=m;i++)cin>>L[i]>>R[i];
	

	ll l=1,r=maxW;
	while(l<=r){
		ll mid=(l+r)/2;
		ll num=calc(mid);
		if(num>S)l=mid+1;
		else r=mid-1;
		ans=min(ans,llabs(S-num));
	}
	
	cout<<ans;
	return 0;
}

  

3.观光公交

题目:https://www.luogu.com.cn/problem/P1315

解析:

贪心思路,定义几个数组,分别表示时间、前缀和、编号等,模拟k次,每次进行更改,最终就是答案

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e4+39+7;
ll n,m,k,ans,t[N],tt[N],l[N],r[N],ww[N],ss[N],ti[N],g[N];
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<n;i++)cin>>t[i];
	for(int i=1;i<=m;i++)cin>>tt[i]>>l[i]>>r[i];
	for(int i=1;i<=m;i++){
		ww[l[i]]=max(ww[l[i]],tt[i]);
		ss[r[i]]++;
	}
	for(int i=1;i<=n;i++)ss[i]+=ss[i-1];
	for(int i=2;i<=n;i++)ti[i]=max(ww[i-1],ti[i-1])+t[i-1];
	for(int i=1;i<=m;i++)ans+=ti[r[i]]-tt[i];
	if(!k){
		cout<<ans;
		return 0;
	}
	while(k--){
		g[n]=n;g[n-1]=n;
		for(int i=n-2;i>=1;i--){
			if(ti[i+1]<=ww[i+1])g[i]=i+1;
			else g[i]=g[i+1];
		}
		ll maxn=0,maxid=0;
		for(int i=1;i<n;i++){
			if(ss[g[i]]-ss[i]>maxn&&t[i]>0){
				maxn=ss[g[i]]-ss[i];
				maxid=i;
			}
		}
		t[maxid]--;
		ans-=maxn;
		for(int i=1;i<=n;i++)ti[i]=max(ww[i-1],ti[i-1])+t[i-1];
	}
	cout<<ans;
	return 0;
}