Codeforces 1188E Problem from Red Panda (计数)

题目链接

https://codeforces.com/contest/1188/problem/E

题解

我们可以发现,题目要求数的目标状态的个数,实际上就是在数操作序列(指每个气球操作的次数构成的序列,第 \(i\) 个颜色操作 \(b_i\) 次)的个数。可以发现如果给定了操作序列,每次一定是操作那个剩下的 \(a_i\) 最小的。那么对于一个合法序列 \(b\),将其每个元素减去 \(1\) 后一定合法,且得到的序列不变。那么我们可以通过强制至少一个 \(b_i=0\) 来保证不算重。
然后我就卡住了。。。。。手动再见
考虑每种颜色对序列合法的限制,就是对每个 \(i\),前 \(a_i+mk+1 (m=0,1,2,...)\) 次操作至少要有一次操作 \(i\). 那么从小到大枚举操作总数 \(s\) (\(0\le s\le \max a_i\)),我们可以得到某些必须进行的操作,剩余的操作分配给 \(k\) 种颜色,使用插板法计算。为了保证存在 \(b_i=0\),再减去强制给每个未出现限制的 \(b_i\)\(+1\) 的方案数。
时间复杂度 \(O(k+\max a_i)\).

代码

#include<bits/stdc++.h>
#define llong long long
#define mkpr make_pair
#define iter iterator
#define riter reversed_iterator
#define y1 Lorem_ipsum_dolor
using namespace std;

inline int read()
{
	int x = 0,f = 1; char ch = getchar();
	for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
	for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;}
	return x*f;
}

const int mxN = 1e6;
const int P = 998244353;
llong fact[mxN*2+3],facti[mxN*2+3];
int a[mxN+3];
int cnt[mxN+3],cnt2[mxN+3];
int n,mx;

llong quickpow(llong x,llong y)
{
	llong cur = x,ret = 1ll;
	for(int i=0; y; i++)
	{
		if(y&(1ll<<i)) {y-=(1ll<<i); ret = ret*cur%P;}
		cur = cur*cur%P;
	}
	return ret;
}
llong comb(llong x,llong y) {return x<0||y<0||x<y?0ll:fact[x]*facti[y]%P*facti[x-y]%P;}

void updsum(llong &x,const llong y) {x = x+y>=P?x+y-P:x+y;}

void initfact(int n)
{
	fact[0] = 1ll; for(int i=1; i<=n; i++) fact[i] = fact[i-1]*i%P;
	facti[n] = quickpow(fact[n],P-2); for(int i=n-1; i>=0; i--) facti[i] = facti[i+1]*(i+1ll)%P;
}

int main()
{
	initfact(mxN*2);
	n = read();
	for(int i=1; i<=n; i++) a[i] = read(),mx = max(mx,a[i]);
	for(int i=1; i<=n; i++)
	{
		for(int j=a[i]+1; j<=mx; j+=n) {cnt[j]++;} cnt2[a[i]+1]++;
	}
	llong ans = 0ll;
	for(int i=0,j=0,k=n; i<=mx; i++,j++)
	{
		j-=cnt[i],k-=cnt2[i];
//		printf("i=%d j=%d k=%d\n",i,j,k);
		if(j<0) break;
		llong tmp = comb(j+n-1,n-1);
		updsum(ans,tmp);
		if(j-k>=0)
		{
			llong tmp = comb(j-k+n-1,n-1);
			updsum(ans,P-tmp);
		}
	}
	printf("%I64d\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
牙科就诊管理系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的Mysql数据库进行程序开发。实现了用户在线查看数据。管理员管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等功能。牙科就诊管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 管理员在后台主要管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等。 牙医列表页面,此页面提供给管理员的功能有:查看牙医、新增牙医、修改牙医、删除牙医等。公告信息管理页面提供的功能操作有:新增公告,修改公告,删除公告操作。公告类型管理页面显示所有公告类型,在此页面既可以让管理员添加新的公告信息类型,也能对已有的公告类型信息执行编辑更新,失效的公告类型信息也能让管理员快速删除。药品管理页面,此页面提供给管理员的功能有:新增药品,修改药品,删除药品。药品类型管理页面,此页面提供给管理员的功能有:新增药品类型,修改药品类型,删除药品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值