Codeforces Round #654 1371E2.Asterism (Hard Version)

题目描述:
E2. Asterism (Hard Version)
time limit per test 1 second
memory limit per test 256 megabytes

This is the hard version of the problem. The difference between versions is the constraints on n and ai. You can make hacks only if all versions of the problem are solved.

First, Aoi came up with the following idea for the competitive programming problem:

Yuzu is a girl who collecting candies. Originally, she has x candies. There are also n enemies numbered with integers from 1 to n. Enemy i has ai candies.

Yuzu is going to determine a permutation P. A permutation is an array consisting of n distinct integers from 1 to n in arbitrary order. For example, {2,3,1,5,4} is a permutation, but {1,2,2} is not a permutation (2 appears twice in the array) and {1,3,4} is also not a permutation (because n=3 but there is the number 4 in the array).

After that, she will do n duels with the enemies with the following rules:

If Yuzu has equal or more number of candies than enemy Pi, she wins the duel and gets 1 candy. Otherwise, she loses the duel and gets nothing.
The candy which Yuzu gets will be used in the next duels.
Yuzu wants to win all duels. How many valid permutations P exist?

This problem was easy and wasn’t interesting for Akari, who is a friend of Aoi. And Akari made the following problem from the above idea:

Let’s define f(x) as the number of valid permutations for the integer x.

You are given n, a and a prime number p≤n. Let’s call a positive integer x good, if the value f(x) is not divisible by p. Find all good integers x.

Your task is to solve this problem made by Akari.

Input
The first line contains two integers n, p (2≤p≤n≤105). It is guaranteed, that the number p is prime (it has exactly two divisors 1 and p).

The second line contains n integers a1,a2,…,an (1≤ai≤109).

Output
In the first line, print the number of good integers x.

In the second line, output all good integers x in the ascending order.

It is guaranteed that the number of good integers x does not exceed 105.

Examples
input

3 2
3 4 5

output

1
3

input

4 3
2 3 5 6

output

2
3 4

input

4 3
9 1 1 1

output

0

input

3 2
1000000000 1 999999999

output

1
999999998

Note
In the first test, p=2.

If x≤2, there are no valid permutations for Yuzu. So f(x)=0 for all x≤2. The number 0 is divisible by 2, so all integers x≤2 are not good.
If x=3, {1,2,3} is the only valid permutation for Yuzu. So f(3)=1, so the number 3 is good.
If x=4, {1,2,3},{1,3,2},{2,1,3},{2,3,1} are all valid permutations for Yuzu. So f(4)=4, so the number 4 is not good.
If x≥5, all 6 permutations are valid for Yuzu. So f(x)=6 for all x≥5, so all integers x≥5 are not good.
So, the only good number is 3.

In the third test, for all positive integers x the value f(x) is divisible by p=3.

算法标签:思维

题目大意:给出n个敌人,每个敌人有ai个糖果,你一开始手中有x个糖果,每次只能选择糖果数小于你当前手中糖果的敌人,战胜他并获得一颗糖果。选择敌人的顺序构成一个排列P。 f ( x ) f(x) f(x)表示一开始有x个糖果时,可行的排列方案数。给出一个素数 p ( p ⩽ n ) p(p\leqslant n) p(pn),求出所有满足 f ( x )   m o d   p ≠ 0 f(x)\ mod\ p\not= 0 f(x) mod p=0的x。

(。。题目就够绕的)

一道“就算知道结论也没那么容易写对”的结论题。

首先给出结论:

若答案存在,则满足条件的x一定是区间 [ s , t ] [s,t] [s,t]之间连续的整数,其中s是使得 f ( x ) ≠ 0 f(x) \not= 0 f(x)=0的最小的x。

为了推导出这个结论需要先处理几个子问题

1.直观上先考虑两端的情况。

若x非常小,无论怎样排列都不能战胜所有敌人,方案数为0,即 f ( x ) = 0 f(x)=0 f(x)=0,x不符合条件。

若x非常大( x > m a x { a i } x>max\{ai\} x>max{ai}),任何排列都是合法的,方案数为全排列 f ( x ) = P n n = n ! f(x)=P^{n}_n=n! f(x)=Pnn=n!,由p<=n这一条件可知,x不符合条件。

因此我们可以把讨论范围限定在 f ( x ) ≠ 0 f(x)\not=0 f(x)=0 x < = m a x { a i } x<=max\{ai\} x<=max{ai}的范围里(以下的讨论都在此范围内)

2. 给定 x x x,怎么求 f ( x ) f(x) f(x)
假设cnt[i]表示 ai中小于i的数的个数,且初始糖果数为x
将ai从小到大排序,依次考虑可能的位置
第i个人可能的位置数为cnt[x+i-1]-i+1(第i个人必须在前cnt[x+i-1]个位置里,且之前已经填了 i-1个人了,还剩下的就是cnt[x+i-1]-i+1)
于是
f ( x ) = ∏ i = 1 n ( c n t [ x + i − 1 ] − i + 1 ) = ∏ i = 0 n − 1 ( c n t [ x + i ] − i ) f(x)=\prod_{i=1}^{n}(cnt[x+i-1]-i+1)=\prod_{i=0}^{n-1}(cnt[x+i]-i) f(x)=i=1n(cnt[x+i1]i+1)=i=0n1(cnt[x+i]i)

为了便于描述,将 c n t [ x + i ] − i cnt[x+i]-i cnt[x+i]i记作 C i ( x ) C_i(x) Ci(x)

3.若存在某项 C i ( x ) ≥ p C_i(x)\ge p Ci(x)p,则一定存在某项 C j ( x ) = p C_j(x)=p Cj(x)=p

因为 C n ( x ) < = 1 C_n(x)<=1 Cn(x)<=1(最后一项可供选择的位置唯一),且 C ( x ) C(x) C(x)每次最多减少1,可知若 C i ( x ) ≥ p C_i(x)\ge p Ci(x)p,在 [ i , n ] [i,n] [i,n]之间一定存在 j j j,使得 C j ( x ) = p C_j(x)=p Cj(x)=p

再推一步,若存在 C i ( x ) ≥ p C_i(x)\ge p Ci(x)p,则一定有 f ( x )   m o d   p = 0 f(x)\ mod \ p=0 f(x) mod p=0,x不满足条件。

4. C i ( x ) ≤ C i ( x + 1 ) C_i(x)\le C_i(x+1) Ci(x)Ci(x+1) 始终满足

由cnt[i]的单调不递减性显然得出。

5.当且仅当存在某项 C i ( x ) = p C_i(x)=p Ci(x)=p时, f ( x )   m o d   p = 0 f(x)\ mod \ p=0 f(x) mod p=0

由p是素数这一条件可知,满足条件的 x x x一定存在 C i ( x ) C_i(x) Ci(x)为p的倍数。结合第3条可知一定存在 C i ( x ) = p C_i(x)=p Ci(x)=p

6. 如果 f ( x )   m o d   p = 0 f(x)\ mod \ p=0 f(x) mod p=0,则 f ( x + 1 )   m o d   p = 0 f(x+1)\ mod \ p=0 f(x+1) mod p=0

结合第3、4、5条可知。

解决以上问题之后结论其实就容易推导了。

考虑使得 f ( x ) ≠ 0 f(x)\not=0 f(x)=0的最小的x,令它为s。

f ( s )   m o d   p = 0 f(s)\ mod \ p=0 f(s) mod p=0,可知存在 C i ( s ) ≥ p C_i(s)\ge p Ci(s)p,那么对于任意 k > s k>s k>s,都存在 C i ( k ) ≥ p C_i(k)\ge p Ci(k)p,也就是没有答案,直接输出0。

f ( s )   m o d   p ≠ 0 f(s)\ mod \ p\not=0 f(s) mod p=0,一旦某个 k ( k > s ) k(k>s) k(k>s),满足 f ( k )   m o d   p = 0 f(k)\ mod \ p=0 f(k) mod p=0,那么所有大于等于 k k k的数都不符合条件。

于是所有符合条件的x一定是连续的,并且若有解,左界一定从s开始。

第二个问题:怎样找到答案的右界t呢?

我们以t=max{ai}的情况为起点。此时 f ( t ) = ∏ i = 0 n − 1 C i ( t ) = n ! f(t)=\prod_{i=0}^{n-1}C_i(t)=n! f(t)=i=0n1Ci(t)=n!

我们把 C n ( t ) C_n(t) Cn(t)的值列个表格看一下。

i C i ( t ) C_i(t) Ci(t)
0n
1n-1
n-12
n1

此时因为存在 C i ( t ) ≥ p C_i(t)\ge p Ci(t)p,所以t不符合条件。

所以只要不断减少t,直到 C i ( x ) < p C_i(x)<p Ci(x)<p对每个 C i ( x ) C_i(x) Ci(x)都成立,此时的t就是右界了。因为 C i ( t ) C_i(t) Ci(t)只会随t减小而减小,所以只需要对每个 C i ( t ) C_i(t) Ci(t)做一次贪心就能找到t了。

最后代码实现的时候会发现一个问题, 因为ai的范围是1~1e9,也就意味着cnt[i]也需要开到1e9的空间。。?

我们令 m x = m a x { a i } mx=max\{ai\} mx=max{ai}。实际上,我们只需要考虑 [ m x − n + 1 , m x ] [mx-n+1,mx] [mxn+1,mx]这个区间内的ai。

为了“战胜所有人”,我们的起始糖果数最少需要mx-n+1个。(否则方案数为0)对于小于等于mx-n的数,总是可以在第一次就选择它,因此可以直接视作0。对于在 [ m x − n + 1 , m x ] [mx-n+1,mx] [mxn+1,mx]区间内的数,做一次处理 a i = a i − m x + n a_i=a_i-mx+n ai=aimx+n,因为 n ≤ 1 e 5 n\leq 1e5 n1e5,这样一来就可以将数据范围限制在 [ 0 , 1 e 5 ] [0,1e5] [0,1e5]之间,相应的cnt[i]也就只需要开到1e5,最后输出答案时再把原来的数还原即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=2e5+5,INF=0x3f3f3f3f,MOD=1e9+7;

int T,n,m,p,A[N],cnt[N];

int s,t,l,r,mx;

bool check(int x)
{
    int now=1;
    for (int i=0;i<n;i++) now=(now*(cnt[i+x]-i))%p;
    return now!=0;
}
int main()
{
    cin>>n>>p;
    for (int i=1;i<=n;i++) scanf("%d",&A[i]);
    sort(A+1,A+1+n);
    mx=A[n];
    for (int i=1;i<=n;i++)
        A[i]=max(A[i]-mx+n,0),cnt[A[i]]++;
    for (int i=1;i<N;i++) cnt[i]+=cnt[i-1];
    for (int i=n;i>=1;i--) s=max(s,A[i]-(i-1));
    if (!check(s))
    {
        printf("0\n");
        return 0;
    }
    t=A[n];
    for (int i=0;i<n;i++) 
    	while (cnt[i+t]-i>=p) t--;
    printf("%d\n",t-s+1);
    for (int i=s;i<=t;i++) printf("%d ",i+mx-n);
    return 0;
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值