分配学号
已经提交 已经通过 时间限制:1000ms 内存限制:256MB
84.41%
提交人数:186
通过人数:157
题目描述
今天,是JWJU给同学们分配学号的一天!为了让大家尽可能的得到自己想要的学号,鸡尾酒让大家先从 [1,10^{18}][1,1018] 中随机挑选一个数字作为自己的学号。但是总有一些心有灵犀的小伙伴们选择了一样的数字——显然这样是不合法的,因为每个人的学号都应该是唯一的。
于是鸡尾酒决定调整大家的学号。他采用如下两个原则来修改:
1、只增不减,每个人的最终学号 ≥ 每个人初始选择的学号
2、总修改量尽量少,总修改量指每一个人的改动量之和。(改动量即为最终学号减初始学号的值)
注意,修改后的最终学号可以大于10^{18}1018。
很显然,如果现在有两个同学 A 和 B,初始选择的学号均为1号,他们有可能被鸡尾酒改动成 A 同学为 11 号和 B 同学为 22 号,或者改动成 B 同学为 11 号和 A 同学为 22 号。
鸡尾酒邪魅一笑,他想让你告诉他,大家的最终学号共有多少种不同的分配方案。
输入描述
第一行包含一个正整数 nn,代表学生的数量。(1 \le n \le 10^{5})(1≤n≤105)
接下来一行包含 nn 个正整数,分别代表每个学生的初始选择的学号。(取值范围[1,10^{18}])[1,1018])
输出描述
输出一个整数表示最终学号的方案数。(答案对 10^{9}+7109+7 取模)
在两个最终学号的分配方案中,若存在某一个学生在两个方案中的学号不相同,则认为是这两个方案是不同的分配方案。
样例输入 1
3 1 1 2
样例输出 1
4
样例输入 2
2 1 5
样例输出 2
1
提示
对于第一组样例,最终的学号分配方案有以下4种:
[1,2,3], [1,3,2], [2,1,3], [3,1,2][1,2,3],[1,3,2],[2,1,3],[3,1,2]
分配之后每个学生的学号均不相同,且这几种方案的总修改量都是最小的。
对于第二组样例,每个学生的学号已经都不相同,所以无需修改,所以最终分配方案只有11种,即[1,5][1,5]。
题意:不解释
题解:首先想满足两个条件,第一个简单,增加就好,主要是第二个,怎么办,我们可以分块来写,然后对块内进行组合数学分步乘法,当然要先排序~~
举个例子怎么保证最小:1 1 2 3 7 7 我们分成1 1 2 3 7 7 两块,显然这样对块内处理就能保证总修改最小,分块的条件是 前面的数字个数 < 下一块的第一个数 比如举的例子 1 1 2 3 数字个数4 < 7 这样就进入下一块,否则就是在块内~~详细请看代码哦~~
上代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX = 1e5+6;
const int mod = 1e9+7;
ll a[MAX];
int main(){
int n;
scanf("%d",&n);
for (int i = 0; i < n;i++){
scanf("%lld",&a[i]);
}
sort(a,a+n);
ll ans=1;
for (int i = 0,j; i < n; i = j){
for (j = i+1; j < n&&a[i]+j-i>=a[j];j++){//分块
ans=(ans*(a[i]+j-i-a[j]+1))%mod;//组合数学分步乘法(块内操作)
}
}
cout << ans << endl;
return 0;
}
本文探讨了一个关于分配学号的算法问题,旨在确保每位学生获得唯一且满足特定条件的学号。通过分析和理解题目的核心需求,文章提出了有效的解决方案,包括如何在保持学号递增的前提下,最小化学号调整的总变动量。通过分块和组合数学的方法,文章给出了具体的实现思路和代码示例。
834

被折叠的 条评论
为什么被折叠?



