PKUSC签到题

题目大意

给出一个长度为 \(N\) 的序列,序列中有 \(K\) 个数会乘二,对于每个数计算在乘二后大于等于这个数的个数与乘二前没有发生变化的方案数.

分析

思路很清晰,可以将答案分为两个部分计算

当前位置的数没有乘二时

当前位置没有乘二,所以所有大于等于自己的元素是否乘二每有影响,如果一个数小于这个数的一半(不可以等于)那么这个数如果乘二也不会产生影响.于是可以计算出大于等于这个数的个数 \(+\) 小于这个数一半的数的个数.接着只需要通过组合数就可以计算你出来了.

当前位置的数乘二时

用一张图来解释起来比较简单:(下图序列为 \(a=[1,3,3,4,6,7]\))

假如开始时的排完序后的序列是上面这个样子,对于第二个数大于等于它的数的个数为 \(5\) (包括自己).现在需要将它的高度翻倍:



可以发现大于等于它的数的个数只剩下了一个,为了保证大于等于这个数的个数不变,在当前数乘二后必须将大于等于这个数小于这个数乘二的数都乘上二.

虽然最后的序列可能不再是有序的,但是对于这个数大于等于它的数的个数没有改变,可以发现原来小于它的数这时如果乘二并不会影响,大于这个数两倍的数乘二自然也不会产生影响啦,于是又可以通到组合数直接计算了.

组合数部分(会的可以跳过)

看到绝大多数的题解都不会涉及这部分内容,但是为了保证大多数人可以看懂,还是来写一下.

在 \(N\) 个数中选 \(M\) 个数的方案数: \(C_{M}^{N} = \frac{N!}{M!(N-M)!}\) 但是在本题中 \(N,M\) 都是 \(1 \times 10^5\) 级别自然不可以暴力计算,可以发现在这个公式由三个阶乘组成,于是自然会想到预处理阶乘,然后计算逆元.这样就可以做到 \(O(N\log_2N)\) 预处理阶乘和逆元,\(O(1)\) 计算,但是\(O(N\log_2N)\)还是有点慢了(虽然在本题中应该可以过),在一些 \(2 \times 10^6 \leq N\) (差不多)时这个时间复杂度就很容易TLE了,\(a\) 的逆元可以理解为 \(\frac{1}{a}\) 所以说 \(\frac{1}{i!}=\frac{1}{(i+1)!} \times i\),这样就可以先处理出 \(N!\) 的逆元,接着只需要 \(O(N)\) 的时间复杂度就可以计算出逆元了.

代码实现

#include<bits/stdc++.h>
#define REP(i,first,last) for(int i=first;i<=last;++i)
#define DOW(i,first,last) for(int i=first;i>=last;--i)
using namespace std;
const int maxN=3e5+7;
const int mod=998244353;
int Mod(long long a)//写一个Mod函数
{
a%=mod;
a+=mod;
a%=mod;
return a;
}
long long Inv(long long a,int b=mod-2)//计算一个数的逆元,其实就是一个快速幂
{
long long result=1;
while(b)
{
if(b&1)
{
result*=a;
result%=mod;
}
a*=a;
a%=mod;
b/=2;
}
return result;
}
long long fac[maxN];//计算阶乘
long long inv[maxN];//计算逆元
int N,M;
int arr[maxN*2];
int sor[maxN*3];//用来离散化
int sum[maxN*3];
int tot=0;
int k;
map<int,int>Hash;//用来离散化
//因为比较懒,于是就先了一颗权值线段树来维护
struct SegmentTree
{
int sum;
}sgt[maxN*4];
//线段树标准define
#define LSON (now<<1)
#define RSON (now<<1|1)
#define MIDDLE ((left+right)>>1)
#define LEFT LSON,left,MIDDLE
#define RIGHT RSON,MIDDLE+1,right
void PushUp(int now)//合并左右子树的值
{
sgt[now].sum=sgt[LSON].sum+sgt[RSON].sum;
}
void Build(int now=1,int left=1,int right=tot)//建树
{
if(left==right)//叶节点直接赋值
{
sgt[now].sum=sum[left];
return;
}
Build(LEFT);
Build(RIGHT);
PushUp(now);//合并
}
//本题不需要修改
int QueryBigger(int num,int now=1,int left=1,int right=tot)
//计算大于等于的数的个数
{
if(num<=left)
{
return sgt[now].sum;
}
if(right<num)
{
return 0;
}
return QueryBigger(num,LEFT)+QueryBigger(num,RIGHT);
}
int QuerySmaller(int num,int now=1,int left=1,int right=tot)
//计算小于等于的数的个数
{
if(right<=num)
{
return sgt[now].sum;
}
if(num<left)
{
return 0;
}
return QuerySmaller(num,LEFT)+QuerySmaller(num,RIGHT);
}
int QuerySmaller_(int num,int now=1,int left=1,int right=tot)
//计算小于的数的个数
{
if(right<num)
{
return sgt[now].sum;
}
if(num<=left)
{
return 0;
}
return QuerySmaller_(num,LEFT)+QuerySmaller_(num,RIGHT);
}
//用完就清空define,防止与其他地方冲突
#undef LSON
#undef RSON
#undef MIDDLE
#undef LEFT
#undef RIGHT
int main()
{
scanf("%d%d",&N,&k);
int cnt=0;
fac[1]=1;
REP(i,2,N)//预处理阶乘
{
fac[i]=Mod(fac[i-1]*i);
}
inv[N]=Inv(fac[N]);//计算N!的逆元
DOW(i,N-1,0)
{
inv[i]=Mod(inv[i+1]*(i+1));//通过优化以后的方法O(N)计算所有阶乘的逆元
}
REP(i,1,N)
{
scanf("%d",&arr[i]);//对于每个数它与它的两倍和一半会在操作中用到
sor[++cnt]=arr[i];
sor[++cnt]=arr[i]/2;
sor[++cnt]=arr[i]*2;
}
//离散化部分
sort(sor+1,sor+1+cnt);
sor[0]=-114514233;
REP(i,1,cnt)
{
if(sor[i]!=sor[i-1])
{
Hash[sor[i]]=++tot;
}
}
REP(i,1,N)//将数放入
{
sum[Hash[arr[i]]]++;
}
Build();//建树
long long answer;//计算答案
int all;//当前数不乘二时有多少数乘二不会造成影响
int must;//计算如果当前数乘二时有多少数必须乘二
int p,q;//计算时需要用到的一些变量
REP(i,1,N)
{
all=QueryBigger(Hash[arr[i]]);//大于等于自身的数的个数肯定不会影响
if(arr[i]&1)all+=QuerySmaller(Hash[arr[i]/2]);//这里需要根据这个数奇偶性查询乘二后仍然小于这个数的个数
else all+=QuerySmaller_(Hash[arr[i]/2]);
all-=1;//将自己减去
answer=Mod(Mod(fac[all]*inv[k])*inv[all-k]);//通过组合数公式计算方案数
if(arr[i]==0)must=1;else//需要特判一下0
must=QuerySmaller_(Hash[arr[i]*2])-QuerySmaller_(Hash[arr[i]]);//必须乘二的数的个数为小于这个数乘二的数的个数-小于这个数的数的个数
if(must<=k)//如果可以做到全部乘二
{
p=N-must;//乘二不会造成影响的数的个数
q=k-must;//还可以有几个数乘二
answer+=Mod(Mod(fac[p]*inv[q])*inv[p-q]);//计算方案数
}
printf("%lld\n",answer%mod);//输出答案
}
return 0;
}

「Luogu P5368 [PKUSC2018]真实排名」的更多相关文章

  1. Luogu P5368 [PKUSC2018]真实排名

    老年选手只会做SB题了(还调了好久) 很容易想到分类讨论,按第\(i\)个人有没有翻倍来算 若\(a_i\)未翻倍,显然此时将\([0,\lceil \frac{a_i}{2}\rceil)\)的数和 ...

  2. 【LOJ4632】[PKUSC2018]真实排名

    [LOJ4632][PKUSC2018]真实排名 题面 终于有题面啦!!! 题目描述 小 C 是某知名比赛的组织者,该比赛一共有 \(n\) 名选手参加,每个选手的成绩是一个非负整数,定义一个选手的排 ...

  3. [PKUSC2018]真实排名

    [PKUSC2018]真实排名 题目大意: 有\(n(n\le10^5)\)个人,每个人有一个成绩\(A_i(0\le A_i\le10^9)\).定义一个人的排名为\(n\)个人中成绩不小于他的总人 ...

  4. BZOJ_5368_[Pkusc2018]真实排名_组合数

    BZOJ_5368_[Pkusc2018]真实排名_组合数 Description 小C是某知名比赛的组织者,该比赛一共有n名选手参加,每个选手的成绩是一个非负整数,定义一个选手的排名是:成绩不小于他 ...

  5. [PKUSC2018]真实排名——线段树+组合数

    题目链接: [PKUSC2018]真实排名 对于每个数$val$分两种情况讨论: 1.当$val$不翻倍时,那么可以翻倍的是权值比$\frac{val-1}{2}$小的和大于等于$val$的. 2.当 ...

  6. bzoj5368 [Pkusc2018]真实排名

    题目描述: bz luogu 题解: 组合数计数问题. 首先注意排名指的是成绩不小于他的选手的数量(包括他自己). 考虑怎么增大才能改变排名. 小学生都知道,对于成绩为$x$的人,让他自己不动并让$\ ...

  7. BZOJ5368:[PKUSC2018]真实排名(组合数学)

    Description 小C是某知名比赛的组织者,该比赛一共有n名选手参加,每个选手的成绩是一个非负整数,定义一个选手的排名是:成绩不小于他的选手的数量(包括他自己). 例如如果333位选手的成绩分别 ...

  8. bzoj 5368: [Pkusc2018]真实排名

    Description 小C是某知名比赛的组织者,该比赛一共有n名选手参加,每个选手的成绩是一个非负整数,定义一个选手的排名是 :成绩不小于他的选手的数量(包括他自己).例如如果3位选手的成绩分别是[ ...

  9. 【洛谷5368】[PKUSC2018] 真实排名(组合数学)

    点此看题面 大致题意: 有\(n\)个数字,定义一个数的排名为不小于它的数的个数.现要随机将其中\(k\)个数乘\(2\),求对于每个数有多少种方案使其排名不变. 分类讨论 对于这种题目,我们可以分类 ...

随机推荐

  1. DFA 简易正则表达式匹配

    一个只能匹配非常简单的(字母 . + *)共 4 种状态的正则表达式语法的自动机(注意,仅限 DFA,没考虑 NFA): 好久之前写的了,记得有个 bug 一直没解决... #include < ...

  2. python"TypeError: 'NoneType' object is not iterable"错误解析

    尊重原创博主,原文链接:https://blog.csdn.net/dataspark/article/details/9953225 [解析] 一般是函数返回值为None,并被赋给了多个变量. 实例 ...

  3. AcWing 850. Dijkstra求最短路 II 堆优化版 优先队列 稀疏图

    //稀疏图 点和边差不多 #include <cstring> #include <iostream> #include <algorithm> #include ...

  4. [杭电_HDU] 2013

    #include <iostream> using namespace std; int main() { int n; while (cin >> n) { ; //最终桃子 ...

  5. glog与gflags的windows编译

    参考博客:https://kezunlin.me/post/bb64e398/

  6. svn还原与本地版本回退

    今天遇到了一个情况,由于没及时更新,对整个项目进行了Ctrl+shift+O,提交代码时冲突:然后就先还原项目,导致之前没有冲突的代码也回退了.然后就在eclipse中获取本地的版本记录,并回退 具体 ...

  7. c++中sort函数调用报错Expression : invalid operator <的内部原理

    当我们调用sort函数进行排序时,中的比较函数如果写成如下 bool cmp(const int &a, const int &b) { if(a!=b) return a<b; ...

  8. c# 异常:值不能为 null。 参数名: source

    异常详细信息: System.ArgumentNullException: 值不能为 null.参数名: source 其实问题那就出在 Select() 方法,在 Select 上按 F12 查看定 ...

  9. 在线直播: .NET与物联网主流技术探秘 初识IoT!

    DNT精英论坛暨.NET北京俱乐部是由资深.NET专家和社区活跃分子发起的技术论坛,以“分享.成长.合作.共赢”为原则,致力于打造一个领先的技术分享平台和成长交流生态.本次活动由aelf赞助支持,刘洪 ...

  10. 谁说程序员没有时间关心女朋友的,Python 教你如何掌握女神情绪变化

    很多人都是在朋友圈装死,微博上蹦迪.微信朋友圈已经不是一个可以随意发表心情的地方了,微博才是! 所以你不要傻傻盯着女神的朋友圈发呆啦!本文教你如何用 Python 自动通知女神微博情绪变化,从今天开始 ...