Atcoder CODE FESTIVAL 2016 qual C 的E题 Encyclopedia of Permutations
题意:
对于一个长度为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之和
代码:
//File Name: E.cpp
//Author: long
//Mail: 736726758@qq.com
//Created Time: 2016年10月26日 星期三 10时29分59秒 #include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <math.h>
#include <vector>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MAXN = + ;
const int MOD = (int)1e9 + ;
int p[MAXN],bit1[MAXN],bit2[MAXN],n;
bool use[MAXN];
LL jie[MAXN];
void update(int x,int add,int *bit){
for(int i=x;i<=n;i+=i&-i)
bit[i] += add;
}
int query(int x,int *bit){
int res = ;
for(int i=x;i>;i-=i&-i)
res += bit[i];
return res;
}
struct Seg{
int n,ly;
LL s;
}seg[MAXN << ];
void pushup(int rt){
seg[rt].s = seg[rt<<].s + seg[rt<<|].s;
seg[rt].n = seg[rt<<].n + seg[rt<<|].n;
}
void pushdown(int rt){
if(seg[rt].ly){
int &ly = seg[rt].ly;
int L = rt<<,R = rt<<|;
seg[L].ly += ly,seg[R].ly += ly;
seg[L].s += (LL)seg[L].n * ly;
seg[R].s += (LL)seg[R].n * ly;
ly = ;
}
}
void build(int l,int r,int rt){
seg[rt].s = seg[rt].ly = seg[rt].n = ;
if(l == r){
if(!use[l]) seg[rt].n = ;
return ;
}
int m = l + r >> ;
build(lson);
build(rson);
pushup(rt);
}
void update(int L,int R,int add,int l,int r,int rt){
if(L <= l && R >= r){
seg[rt].ly += add;
seg[rt].s += (LL)add * seg[rt].n;
return ;
}
pushdown(rt);
int m = l + r >> ;
if(L <= m) update(L,R,add,lson);
if(R > m) update(L,R,add,rson);
pushup(rt);
}
int init(){
build(,n,);
jie[] = ;
for(int i=;i<=n;i++)
jie[i] = jie[i-] * i % MOD;
int sum = ;
for(int i=;i<=n;i++){
if(!use[i]){
update(i,,bit2);
sum++;
}
}
return sum;
}
LL solve(){
int sum = init();
LL ans = ,tmp1,tmp2;
int suf = ;
for(int i=n;i>;i--){
tmp1 = tmp2 = ;
// ans = 0;
if(p[i]){
int x = query(p[i] - ,bit1);
tmp1 = x * jie[sum] % MOD * jie[n - i] % MOD;
int y = query(p[i],bit2);
if(sum >= )
tmp2 = (LL)y*suf % MOD * jie[sum-] % MOD * jie[n-i] % MOD;
ans = (ans + tmp1 + tmp2) % MOD;
update(p[i],,bit1);
if(p[i] < n) update(p[i]+,n,,,n,);
}
else{
if(sum >= )
tmp1 = ((LL)sum * (sum - ) / ) % MOD * jie[sum-] % MOD * suf % MOD * jie[n-i] % MOD;
if(sum >= )
tmp2 = seg[].s % MOD * jie[sum-] % MOD * jie[n-i] % MOD;
// printf("tmp1 = %lld\ntmp2 = %lld\n",tmp1,tmp2);
ans = (ans + tmp1 + tmp2) % MOD;
suf++;
}
// printf("i = %d ans = %lld\n",i,ans);
}
// cout << jie[sum] << endl;
ans = (ans + jie[sum]) % MOD;
return ans;
}
int main(){
scanf("%d",&n);
memset(use,false,sizeof(use));
for(int i=;i<=n;i++){
scanf("%d",p + i);
use[p[i]] = true;
}
printf("%d\n",(int)solve());
return ;
}
Atcoder CODE FESTIVAL 2016 qual C 的E题 Encyclopedia of Permutations的更多相关文章
- 【AtCoder】CODE FESTIVAL 2016 qual A
CODE FESTIVAL 2016 qual A A - CODEFESTIVAL 2016 -- #include <bits/stdc++.h> #define fi first # ...
- 【AtCoder】CODE FESTIVAL 2016 qual B
CODE FESTIVAL 2016 qual B A - Signboard -- #include <bits/stdc++.h> #define fi first #define s ...
- 【AtCoder】CODE FESTIVAL 2016 qual C
CODE FESTIVAL 2016 qual C A - CF -- #include <bits/stdc++.h> #define fi first #define se secon ...
- Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution
Atcoder CODE FESTIVAL 2016 Grand Final E - Water Distribution 题目链接:https://atcoder.jp/contests/cf16- ...
- Atcoder CODE FESTIVAL 2017 qual B D - 101 to 010 dp
题目链接 题意 对于一个\(01\)串,如果其中存在子串\(101\),则可以将它变成\(010\). 问最多能进行多少次这样的操作. 思路 官方题解 转化 倒过来考虑. 考虑,最终得到的串中的\(' ...
- 题解【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 串 ...
- 【题解】Popping Balls AtCoder Code Festival 2017 qual B E 组合计数
蒟蒻__stdcall终于更新博客辣~ 一下午+一晚上=一道计数题QAQ 为什么计数题都这么玄学啊QAQ Prelude 题目链接:这里是传送门= ̄ω ̄= 下面我将分几个步骤讲一下这个题的做法,大家不 ...
- atcoder/CODE FESTIVAL 2017 qual B/B(dfs染色判断是否为二分图)
题目链接:http://code-festival-2017-qualb.contest.atcoder.jp/tasks/code_festival_2017_qualb_c 题意:给出一个含 n ...
- Atcoder CODE FESTIVAL 2017 qual C D - Yet Another Palindrome Partitioning 回文串划分
题目链接 题意 给定一个字符串(长度\(\leq 2e5\)),将其划分成尽量少的段,使得每段内重新排列后可以成为一个回文串. 题解 分析 每段内重新排列后是一个回文串\(\rightarrow\)该 ...
随机推荐
- URAL 2080 Wallet 莫队算法
题目链接:Wallet 题意:给出n张卡片,k次使用.要求每次使用的卡片都在最上面.首先希望你合理的安排每张卡片的初始位置,并且输出.然后,问每次使用完卡片之后插入的位置上面有几张卡片,才能使得每次使 ...
- 使用Markdown+Pandoc+LaTex+Beamer制作幻灯片
概述 为什么使用markdown? mardown是一种轻量级的标记语言,语法简单,可读性好,并且容易转化成其他格式的文档, 在技术文档撰写中得到越来越广泛的应用.相信大家对markdown都有一定了 ...
- 转: 我们为什么使用ORM?
博客园在推广ORM方面的确做了很大的贡献,很多的程序员开始使用ORM,不用写SQL的喜悦让他们激动不已,可是好景不长,他们很快发现众多的烦恼一个接一个的出现了. 很遗憾,我并不打算在这篇文章中解决这些 ...
- Quartus ii 12.0 和ModelSim 10.1 SE安装及连接
quartus ii 10.0后就没有自带的仿真软件,每次写完一个VerilogHDL都想简单仿真一下,结果发现没有了自带仿真软件.这时候就需要第三方仿真软件ModelSim 10.1 SE. Qua ...
- sql like in 语句获取以逗号分割的字段内的数据
From:http://www.cnblogs.com/goody9807/archive/2011/07/27/2118107.html sql中的某个字段用“,”分隔数据,需要获取数据的时候直接把 ...
- Oracle 分析函数之 lag和lead
Lag和Lead分析函数可以在同一次查询中取出同一字段的前N行的数据(Lag)和后N行的数据(Lead)作为独立的列. 这种操作可以代替表的自联接,并且LAG和LEAD有更高的效率. /*语法*/ ...
- c/c++面试题(3)strcat/strcmp/strlen/strcpy的实现
1.编写一个函数实现strlen以及strcpy函数. strcpy函数. 后面的字符串拷贝到一个字符数组中,要求拷贝好的字符串在字符数组的首 地址,并且只拷贝到'\0'的位置.原型是 char* m ...
- 谷歌浏览器中安装.crx扩展名的离线Chrome插件
一.本地拖放安装 1.下载扩展程序/脚本程序至本地计算机: 2.将其直接拖拽到浏览器的“扩展程序”(chrome://chrome/extensions/)页面. 二.解决“只能通过Chrome网上应 ...
- zookeeper命令行(zkCli.sh&zkServer.sh)使用及四字命令
zookeeper提供了很多方便的功能,方便我们查看服务器的状态,增加,修改,删除数据(入口是zkServer.sh和zkCli.sh). 还提供了一系列四字命令,方便我们跟服务器进行各种交互,来确认 ...
- read.csv 把 "T" 读成 "TRUE" 的问题
read.csv(text="A,B,T,T", header=FALSE) ## V1 V2 V3 V4 ## 1 A B TRUE TRUE RT, 有的时候R读取数据的时候容 ...