题意:

对于一个长度为n的排列P,如果P在所有长度为n的排列中,按照字典序排列后,在第s位,则P的value为s

现在给出一个长度为n的排列P,P有一些位置确定了,另外一些位置为0,表示不确定。

现在问,P的所有可能的排列的value之和

n <= 500000

思路:

对于一个可能的排列,它的value为所有小于它的排列的个数 + 1反过来,对于一个排列a,如果P的可能的排列中有sum个排列大于a,则a对答案的贡献为sum

那我们就可以枚举位数,

一位一位的考虑:

对于2个排列P,b,我们假设它在第i位分出大小,即[1,i-1]的位置2个排列相同,并且第i位有P[i]  > b[i]

并且P就是满足条件的可能的排列,那我们算出这个时候有x个可能的P,y个可能的b,则对答案的贡献

为x * y

为了方便,我们从后面往前面枚举

那对于位数i,我们只需要分2 * 2种情况考虑:

自由的数表示没有被固定位置的数

suf表示i后面有多少个没有被确定的位置

sum表示P一共有多少个没有被确定的位置

1. Pi的位置确定了

1.1 b在i处放的数为[1,P[i]-1]中被固定在[i+1,n]中某一位的数,设有x个,则贡献:

   x * sum! * (n - i)!

  求x的话用一个树状数组bit记录就可以了,遇见固定的数就扔进bit里面

1.2   b在i处放的数为[1,P[i]-1]中自由的数,设有y个,则贡献:

  y * suf * (sum - 1)! * (n - i)!

  提前把所有自由的数放到一个树状数组bit2中,就可以快速得到y了

2 P[i]处的数没有确定

2.1 b在i处放的数也是自由的数,则贡献:

  C(sum,2) * (sum - 2)! * suf * (n - i)!

2.2 b在i处放的数是[1,P[i]-1]中被固定在i后面某一位的数

  假设P[i]放的是x,则b[i]放的应该是[1,x-1]中被固定在i后面的数,设[1,x-1]中被固定在i后面的数

  有y个,则贡献:

  y * (sum - 1)! * (n - i)!

  所以这部分的贡献需要我们枚举x,对于每一个x求有多少个y?

  不用,用线段树可以维护,总贡献为:

  seg[1].s * (sum - 1)! * (n - i)!

所以这道题目就搞定了,接下来说说线段树维护的是什么

Seg{int n;int ly;LL s}

线段树只需要维护自由的那一些数,因为枚举的x是自由的数

对于叶子节点i

s表示表示目前被固定的数中,比i小的有多少个

n表示这个叶子节点是不是自由的数

则对于所有节点:

n表示这个区间有多少个自由的数

s表示这个区间的自由的数的s之和

代码:

  1. //File Name: E.cpp
  2. //Author: long
  3. //Mail: 736726758@qq.com
  4. //Created Time: 2016年10月26日 星期三 10时29分59秒
  5.  
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <algorithm>
  9. #include <iostream>
  10. #include <map>
  11. #include <set>
  12. #include <math.h>
  13. #include <vector>
  14. #define LL long long
  15. #define lson l,m,rt<<1
  16. #define rson m+1,r,rt<<1|1
  17. using namespace std;
  18. const int MAXN = + ;
  19. const int MOD = (int)1e9 + ;
  20. int p[MAXN],bit1[MAXN],bit2[MAXN],n;
  21. bool use[MAXN];
  22. LL jie[MAXN];
  23. void update(int x,int add,int *bit){
  24. for(int i=x;i<=n;i+=i&-i)
  25. bit[i] += add;
  26. }
  27. int query(int x,int *bit){
  28. int res = ;
  29. for(int i=x;i>;i-=i&-i)
  30. res += bit[i];
  31. return res;
  32. }
  33. struct Seg{
  34. int n,ly;
  35. LL s;
  36. }seg[MAXN << ];
  37. void pushup(int rt){
  38. seg[rt].s = seg[rt<<].s + seg[rt<<|].s;
  39. seg[rt].n = seg[rt<<].n + seg[rt<<|].n;
  40. }
  41. void pushdown(int rt){
  42. if(seg[rt].ly){
  43. int &ly = seg[rt].ly;
  44. int L = rt<<,R = rt<<|;
  45. seg[L].ly += ly,seg[R].ly += ly;
  46. seg[L].s += (LL)seg[L].n * ly;
  47. seg[R].s += (LL)seg[R].n * ly;
  48. ly = ;
  49. }
  50. }
  51. void build(int l,int r,int rt){
  52. seg[rt].s = seg[rt].ly = seg[rt].n = ;
  53. if(l == r){
  54. if(!use[l]) seg[rt].n = ;
  55. return ;
  56. }
  57. int m = l + r >> ;
  58. build(lson);
  59. build(rson);
  60. pushup(rt);
  61. }
  62. void update(int L,int R,int add,int l,int r,int rt){
  63. if(L <= l && R >= r){
  64. seg[rt].ly += add;
  65. seg[rt].s += (LL)add * seg[rt].n;
  66. return ;
  67. }
  68. pushdown(rt);
  69. int m = l + r >> ;
  70. if(L <= m) update(L,R,add,lson);
  71. if(R > m) update(L,R,add,rson);
  72. pushup(rt);
  73. }
  74. int init(){
  75. build(,n,);
  76. jie[] = ;
  77. for(int i=;i<=n;i++)
  78. jie[i] = jie[i-] * i % MOD;
  79. int sum = ;
  80. for(int i=;i<=n;i++){
  81. if(!use[i]){
  82. update(i,,bit2);
  83. sum++;
  84. }
  85. }
  86. return sum;
  87. }
  88. LL solve(){
  89. int sum = init();
  90. LL ans = ,tmp1,tmp2;
  91. int suf = ;
  92. for(int i=n;i>;i--){
  93. tmp1 = tmp2 = ;
  94. // ans = 0;
  95. if(p[i]){
  96. int x = query(p[i] - ,bit1);
  97. tmp1 = x * jie[sum] % MOD * jie[n - i] % MOD;
  98. int y = query(p[i],bit2);
  99. if(sum >= )
  100. tmp2 = (LL)y*suf % MOD * jie[sum-] % MOD * jie[n-i] % MOD;
  101. ans = (ans + tmp1 + tmp2) % MOD;
  102. update(p[i],,bit1);
  103. if(p[i] < n) update(p[i]+,n,,,n,);
  104. }
  105. else{
  106. if(sum >= )
  107. tmp1 = ((LL)sum * (sum - ) / ) % MOD * jie[sum-] % MOD * suf % MOD * jie[n-i] % MOD;
  108. if(sum >= )
  109. tmp2 = seg[].s % MOD * jie[sum-] % MOD * jie[n-i] % MOD;
  110. // printf("tmp1 = %lld\ntmp2 = %lld\n",tmp1,tmp2);
  111. ans = (ans + tmp1 + tmp2) % MOD;
  112. suf++;
  113. }
  114. // printf("i = %d ans = %lld\n",i,ans);
  115. }
  116. // cout << jie[sum] << endl;
  117. ans = (ans + jie[sum]) % MOD;
  118. return ans;
  119. }
  120. int main(){
  121. scanf("%d",&n);
  122. memset(use,false,sizeof(use));
  123. for(int i=;i<=n;i++){
  124. scanf("%d",p + i);
  125. use[p[i]] = true;
  126. }
  127. printf("%d\n",(int)solve());
  128. return ;
  129. }

Atcoder CODE FESTIVAL 2016 qual C 的E题 Encyclopedia of Permutations的更多相关文章

  1. 【AtCoder】CODE FESTIVAL 2016 qual A

    CODE FESTIVAL 2016 qual A A - CODEFESTIVAL 2016 -- #include <bits/stdc++.h> #define fi first # ...

  2. 【AtCoder】CODE FESTIVAL 2016 qual B

    CODE FESTIVAL 2016 qual B A - Signboard -- #include <bits/stdc++.h> #define fi first #define s ...

  3. 【AtCoder】CODE FESTIVAL 2016 qual C

    CODE FESTIVAL 2016 qual C A - CF -- #include <bits/stdc++.h> #define fi first #define se secon ...

  4. Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution

    Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution 题目链接:https://atcoder.jp/contests/cf16- ...

  5. Atcoder CODE FESTIVAL 2017 qual B D - 101 to 010 dp

    题目链接 题意 对于一个\(01\)串,如果其中存在子串\(101\),则可以将它变成\(010\). 问最多能进行多少次这样的操作. 思路 官方题解 转化 倒过来考虑. 考虑,最终得到的串中的\(' ...

  6. 题解【AtCoder - CODE FESTIVAL 2017 qual B - D - 101 to 010】

    题目:https://atcoder.jp/contests/code-festival-2017-qualb/tasks/code_festival_2017_qualb_d 题意:给一个 01 串 ...

  7. 【题解】Popping Balls AtCoder Code Festival 2017 qual B E 组合计数

    蒟蒻__stdcall终于更新博客辣~ 一下午+一晚上=一道计数题QAQ 为什么计数题都这么玄学啊QAQ Prelude 题目链接:这里是传送门= ̄ω ̄= 下面我将分几个步骤讲一下这个题的做法,大家不 ...

  8. atcoder/CODE FESTIVAL 2017 qual B/B(dfs染色判断是否为二分图)

    题目链接:http://code-festival-2017-qualb.contest.atcoder.jp/tasks/code_festival_2017_qualb_c 题意:给出一个含 n ...

  9. Atcoder CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning 回文串划分

    题目链接 题意 给定一个字符串(长度\(\leq 2e5\)),将其划分成尽量少的段,使得每段内重新排列后可以成为一个回文串. 题解 分析 每段内重新排列后是一个回文串\(\rightarrow\)该 ...

随机推荐

  1. flash透明效果代码分享~~~

    <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://down ...

  2. display 和 visibility 的区别

    设置控件隐藏 1.display:none  不为元素保留位置 2.visibility:hidden  占位置,是对象在网页上看不到,所占空间没有变化

  3. [转]CSS,font-family,常用网页字体

    http://www.zreading.cn/ican/2014/10/css-font-family/ CSS,font-family,好看常用的中文字体 2014-10-14 例1(小米米官网): ...

  4. 做办公用品、文具方面的 B2C 是否有前景呢?

    企乐买现在正在做这方面的事,从市场角度来说需求是有的,客单价和重复购买率都还可以,但是也存在几个致命问题使得施展不开举步维艰: 1.中国特有的市场环境:在美国企业办公用品一般都是网上采购,避免灰色的东 ...

  5. android 使用相机拍照,并存储到手机sd卡上,并利用系统录像录像并播放

    //首先声明一个成员变量 String savePath,用来储存文件路径 /** * 保存照片路径 * @return 返回图片的一个文件 * @throws IOException 抛出一个异常 ...

  6. 【转】Nginx 安装配置

    Nginx("engine x")是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. ...

  7. 向mysql workbench中导入.sql文件

    mysql workbench用的不多,前段时间装了一下,然后用了一下,感觉操作比dbdesigner4要更人性化一点.其中二个方面做了改进,让我觉得很爽. 第一,就是端口可以修改了,以前就是定死33 ...

  8. c语言 四种方法调用数组

      #include <stdio.h> /********************************* * 方法1: 第一维的长度可以不指定 * * 但必须指定第二维的长度 * * ...

  9. 使用python-openCV对摄像头捕捉的镜头进行二值化并打上文字

    用CaptureFromCAM函数对图像进行提取: capture = cv.CaptureFromCAM(0) 读取直接的视频文件只需将语句改变为: capture = cv.VideoCaptur ...

  10. 利用中文数据跑Google开源项目word2vec

    一直听说word2vec在处理词与词的相似度的问题上效果十分好,最近自己也上手跑了跑Google开源的代码(https://code.google.com/p/word2vec/). 1.语料 首先准 ...