[codeforces 1371E2] Asterism (Hard Version) 乘法原理+找规律+二分

Codeforces Round #654 (Div. 2)   参与排名人数14349   本场比赛主要心思放在观摩高手如何打比赛,发现初中生真的很厉害。

[codeforces 1371E2]    Asterism (Hard Version)   乘法原理+找规律+二分

总目录详见https://blog.csdn.net/mrcrack/article/details/103564004

在线测评地址https://codeforces.com/contest/1371/problem/E2

ProblemLangVerdictTimeMemory
E2 - Asterism (Hard Version) GNU C++17Accepted78 ms4300 KB

题目大意:小女孩手上有x颗糖,n个对手,手上的糖的数量,对应数组a中的元素,小女孩可以按照n的排列数,选择需要比较对手的次序。f(x)代表排列书的数量,在这些排列数中,小女孩都能赢。赢的标准是,每次比较时,小女孩手上糖果的数量,大于等于当前对手的糖果数量,若赢,小女孩手上还能增加1颗糖。若f(x)%p!=0(p是输入数据给出的质数),那么记录此时的x,寻找所有可能的x,输出满足条件的x数量,并按升序,输出相应的x值。

样例模拟如下:

3 2
3 4 5

1
3

3的排列数有6种,如下
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

对手位置1 2 3
对手数值3 4 5

x<=2时,因为对手糖果最小值是3,无论如何根据位置的排列数选择对手,
小女孩永远不可能赢,故赢的数量是0,即此时f(x)=0,
此时f(x)%2==0,这个x不是需要的结果,不记录此时的x.


x>=5时,因为对手糖果最大值是5,无论如何根据位置的排列数选择对手,
小女孩永远都能赢,故赢的数量是6,即此时f(x)=6,
但此时f(x)%2==0,这个x不是需要的结果,不记录此时的x.


x=3时,只有根据位置的排列数(1 2 3)选择对手,
比较过程如下
3>=3(位置1),女孩手上糖果变为3+1=4,
4>=4(位置2),女孩手上糖果变为4+1=5,
5>=5(位置3),女孩手上糖果变为5+1=6,
小女孩能赢,故赢的数量是1,即此时f(x)=1,
但此时f(x)%2==1,这个x是需要的结果,记录此时的x=3.

对x=3,用乘法原理进行进一步的解释:
位置1 2 3
数值3 4 5

位置1上对手的糖果数量必须小于等于3,此时只有3,位置1上只有1个数可选择
位置2上对手的糖果数量必须小于等于4,此时只有(之前的3已被位置1占用)4,位置2上只有1个数可选择
位置3上对手的糖果数量必须小于等于5,此时只有(之前的4已被位置2占用)5,位置3上只有1个数可选择
根据乘法原理1*1*1=1,f(3)=1


x=4时,根据位置的排列数
(1 2 3),(1,3,2)
(2,1,3),(2,3,1)
选择对手,
小女孩都能赢,故赢的数量是4,即此时f(x)=4,
但此时f(x)%2==0,这个x是不需要的结果,不记录此时的x.

对x=4,用乘法原理进行进一步的解释:
位置1 2 3
数值3 4 5

位置1上对手的糖果数量必须小于等于4,此时有3、4,位置1上有2个数可选择
位置2上对手的糖果数量必须小于等于5,此时有(3、4)中没被位置1选中的那个,与5,位置2上有2个数可选择
位置3上对手的糖果数量必须小于等于6,此时有(3、4、5)中没被位置1、2选中的那个,位置3上有1个数可选择
根据乘法原理2*2*1=4,f(4)=4


故最后输出如下
1
3

样例继续模拟如下

4 3
2 3 5 6

2
3 4


4的排列数有24种

对手位置1 2 3 4
对手数值2 3 5 6

x<=1时,因为对手糖果最小值是2,无论如何根据位置的排列数选择对手,
小女孩永远不可能赢,故赢的数量是0,即此时f(x)=0,
此时f(x)%3==0,这个x不是需要的结果,不记录此时的x.


x>=6时,因为对手糖果最大值是6,无论如何根据位置的排列数选择对手,
小女孩永远都能赢,故赢的数量是24,即此时f(x)=24,
但此时f(x)%3==0,这个x不是需要的结果,不记录此时的x.


x=2时,就算根据位置的排列数(1 2 3 4)选择对手,小女孩还是输,
故赢的数量是0,即此时f(x)=0,
但此时f(x)%2==0,这个x不是需要的结果,不记录此时的x.

x=3时,根据位置的排列数(1 2 3 4),(2 1 3 4)选择对手,小女孩能赢,
故赢的数量是2,即此时f(x)=2,
但此时f(x)%3==2,这个x是需要的结果,记录此时的x=3.

对x=3,用乘法原理进行进一步的解释:
对手位置1 2 3 4
对手数值2 3 5 6

位置1上对手的糖果数量必须小于等于3,此时有2、3,位置1上只有2个数可选择
位置2上对手的糖果数量必须小于等于4,此时有(2,3)中未被位置1选中的,位置2上只有1个数可选择
位置3上对手的糖果数量必须小于等于5,此时有5,位置3上只有1个数可选择
位置4上对手的糖果数量必须小于等于6,此时有6,位置4上只有1个数可选择
根据乘法原理2*1*1*1=2,f(3)=2


x=4时,根据位置的排列数
(1 2 3 4),(1 2 4 3),(1 3 2 4),(1 3 4 2),
(2 1 3 4),(2 1 4 3),(2 3 1 4),(2 3 4 1)
选择对手,
小女孩能赢,故赢的数量是8,即此时f(x)=8,
但此时f(x)%3==2,这个x是需要的结果,记录此时的x=4.

对x=4,用乘法原理进行进一步的解释:
对手位置1 2 3 4
对手数值2 3 5 6

位置1上对手的糖果数量必须小于等于4,此时有2、3,位置1上有2个数可选择
位置2上对手的糖果数量必须小于等于5,此时有(2,3)中未被位置1选中的,与5,位置2上有2个数可选择
位置3上对手的糖果数量必须小于等于6,此时有(2,3,5)中未被位置1,2选中的,与6,位置3上有2个数可选择
位置4上对手的糖果数量必须小于等于7,此时有(2,3,5,6)中未被位置1,2,3选中的,位置4上只有1个数可选择
根据乘法原理2*2*2*1=8,f(3)=8

x==5时,无论如何根据位置的排列数选择对手,
小女孩永远都能赢,故赢的数量是24,即此时f(x)=24,
但此时f(x)%3==0,这个x不是需要的结果,不记录此时的x.

故最后输出如下
2
3 4


样例继续模拟如下

4 3
9 1 1 1

0

自小到大将对手排序
对手位置1 2 3 4
对手糖果1 1 1 9

要赢,小女孩,在位置1,糖果数量至少是6

x=6,根据乘法原理进行探讨。
位置1上糖果数量不得大于6,可选择的有(1 1 1),3种选择
位置2上糖果数量不得大于7,可选择的有剩下的(1 1),2种选择
位置3上糖果数量不得大于8,可选择的有剩下的(1),1种选择
位置4上糖果数量不得大于9,可选择的有9,1种选择
总的选择是3*2*1*1=6,因计算过程中,包含了因子3,故此种情况不做记录。

x=7,根据乘法原理进行探讨。
位置1上糖果数量不得大于7,可选择的有(1 1 1),3种选择
位置2上糖果数量不得大于8,可选择的有剩下的(1 1),2种选择
位置3上糖果数量不得大于9,可选择的有剩下的(1 9),2种选择
位置4上糖果数量不得大于10,可选择的有剩下的(1 9)未被选中的那个,1种选择
总的选择是3*2*2*1=12,因计算过程中,包含了因子3,故此种情况不做记录。



x=8,根据乘法原理进行探讨。
位置1上糖果数量不得大于8,可选择的有(1 1 1),3种选择
位置2上糖果数量不得大于9,可选择的有剩下的(1 1 9),3种选择
位置3上糖果数量不得大于10,可选择的有剩下的(1 1 9)未被选中的2个,2种选择
位置4上糖果数量不得大于11,可选择的有剩下的(1 1 9)未被选中的那个,1种选择
总的选择是3*3*2*1=18,因计算过程中,包含了因子3,故此种情况不做记录。

x=9,根据乘法原理进行探讨。
位置1上糖果数量不得大于9,可选择的有(1 1 1 9),4种选择
位置2上糖果数量不得大于10,可选择的有剩下的(1 1 1 9未被选中的3个,3种选择
位置3上糖果数量不得大于11,可选择的有剩下的(1 1 1 9)未被选中的2个,2种选择
位置4上糖果数量不得大于12,可选择的有剩下的(1 1 1 9)未被选中的那个,1种选择
总的选择是4*3*2*1=24,因计算过程中,包含了因子3,故此种情况不做记录。

x>9的情况与x=9的情况,完全相同,不在讨论。

很明显,有一处,出现能整除p的情况后,之后,再增大的x,对应的情况都能整除p.

AC代码如下:

#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
int n,p,a[maxn];
int judge(int x){
	int now=1,i;
	for(i=1;i<=n;i++){
		while(now<=n&&a[now]<=x)now++;//now统计数组中不大于x的对手数量
		if((now-i)%p==0)return 1;//bad
		x++;//赢的情况下,x表示小女孩在位置i上的糖果数量,故跳到下一个位置时,需要加1
	}
	return 0;//good
}
int main(){
	int i,maxi,l,r,mid;
	scanf("%d%d",&n,&p);
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	sort(a+1,a+1+n);//自小到大排序
	maxi=-1;
	for(i=1;i<=n;i++)
		maxi=max(maxi,a[i]-i+1);//小女孩要赢时,maxi记录位置1对应的最小糖果数量
	l=maxi-1,r=1000000000;
	while(l+1<r){
		mid=(l+r)/2;
		if(judge(mid))r=mid;
		else l=mid;
	}
	printf("%d\n",l-maxi+1);
	for(i=maxi;i<=l;i++)printf("%d ",i);
	printf("\n");
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值