[JSOI2011]解题报告

[JSOI2011]分特产

一道组合数学+容斥的题目,考虑如何处理掉每个人至少一个这个限制,这时就要容斥一下有多少人没有分到即可,没分到的人数设为\(i\)

每种特产分开算,便转化成了\(n-i-1\)块板子插入\(a[i]\)个中,方案数为\(C(n-i-a[i]-1,n-i-1)\)

那么总的式子便为\(\sum_{i=0}^{n-1}(-1)^iC(n,i)\prod_{j=1}^mC(n-i+a[i]-1,n-i-1)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int jie[10003],cnt=-1,n,m,a[100003],cn,ans;
int poww(int x,int p)
{
	if(p==0)
		return 1;
	int tmp=poww(x,p/2);
	tmp=(tmp*tmp)%mod;
	if(p%2==1)
		tmp=(tmp*x)%mod;
	return tmp;
}
int c(int nn,int mm)
{
	return jie[nn]*poww(jie[mm],mod-2)%mod*poww(jie[nn-mm],mod-2)%mod;
}
signed main()
{
	jie[0]=1;
	for(int i=1; i<=10000; i++)
		jie[i]=jie[i-1]*i%mod;
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%lld",&a[i]);
	for(int i=0;i<n;i++)
	{
		cnt*=-1,cn=1;
		for(int j=1;j<=m;j++)
			cn*=c(n-i+a[j]-1,n-i-1),cn%=mod;
		ans+=cn*c(n,i)%mod*cnt%mod,ans=(ans+mod)%mod;
	}
	cout<<ans;
	return 0;
}

[JSOI2011]棒棒糖

这道题就是用主席树来维护这一个序列的权值,每次询问从\([1,max{c[i]}]\)开始,每次递归\([l,mid]\)\([mid,r]\)查找在这个权值区间内的元素数量,如果数量乘2大于询问区间长度,就在这个权值区间内递归,知道找到一个符合要求的数或者找不到,然后剩下的就是主席树的基本操作

#include<bits/stdc++.h>
using namespace std;
struct node
{
	int l1,r1,sum;
}tr[5000003];
int n,m,s,t,a[50003],gen[50003],summ,su,ans[50003],mp[50003];
inline int rd()
{
	int x=0,p=1;
	char a=getchar();
	while((a<48||a>57)&&a!='-')
		a=getchar();
	if(a=='-')
		p=-p,a=getchar();
	while(a>47&&a<58)
		x=(x<<1)+(x<<3)+(a&15),a=getchar();
	return x*p;
}
int nbuild(int root)
{
	summ++,tr[summ]=tr[root];
	return summ;
}
int build(int l,int r)
{
	summ++;
	int root=summ,mid=(l+r)/2;
	if(l==r)
	{
		tr[root].sum=0;
		return root;
	}
	tr[root].l1=build(l,mid),tr[root].sum=0,tr[root].r1=build(mid+1,r);
	return root;
}
int add(int root,int l,int r,int x)
{
	root=nbuild(root);
	if(l==r)
	{
		tr[root].sum++;
		return root;
	}
	int mid=(l+r)/2;
	if(mid>=x)
		tr[root].l1=add(tr[root].l1,l,mid,x);
	else
		tr[root].r1=add(tr[root].r1,mid+1,r,x);
	tr[root].sum=tr[tr[root].l1].sum+tr[tr[root].r1].sum;
	return root;
}
int ask(int root1,int root2,int l,int r,int x)
{
	if(l==r)
		return l;
	int mid=(l+r)/2;
	if(2*(tr[tr[root2].l1].sum-tr[tr[root1].l1].sum)>x)
		return ask(tr[root1].l1,tr[root2].l1,l,mid,x);
	else if(2*(tr[tr[root2].r1].sum-tr[tr[root1].r1].sum)>x)
		return ask(tr[root1].r1,tr[root2].r1,mid+1,r,x);
	return 0;
}
int main()
{
	n=rd(),m=rd();
	for(int i=1;i<=n;i++)
	{
		a[i]=rd();
		if(mp[a[i]]==0)
			su++,mp[a[i]]=su,ans[su]=a[i];
		a[i]=mp[a[i]];
	}
	gen[0]=build(1,su);
	for(int i=1;i<=n;i++)
		gen[i]=add(gen[i-1],1,su,a[i]);
	for(int i=1;i<=m;i++)
	{
		s=rd(),t=rd();
		printf("%d\n",ans[ask(gen[s-1],gen[t],1,su,t-s+1)]);
	}
	return 0;
}
posted @ 2020-01-31 12:24  dz_ice  阅读(128)  评论(0编辑  收藏  举报