Codeforces Round #445 Div. 1 C Maximum Element (dp + 组合数学)
题目链接:
http://codeforces.com/contest/889/problem/C
题意:
给你 \(n\)和 \(k\)。
让你找一种全排列长度为\(n\)的 \(p\),满足存在下标 \(i\),\(p_i\)大于所有 \(p_j\),\(j\epsilon[1,i-1]\)同时大于所有\(p_i\),\(j\epsilon[i+1,i+k]\)。问你满足这样条件的排列有多少种?
题解:
设\(dp[i]\)表示以 \(i\) 结尾的,满足题目要求的\(1\) ~ \(i\)排列。
显然。
如果,\(i<=k+1\),则\(dp[i]=0\)。
因为我们考虑 \(i-1\) 在这个排列当中的位置。当 \(i-1\) 和 \(i\) 之间的数字超过 \(k\)个时,显然成立,此时共有 \((i-k-1)*(i-2)!\) 种序列。
否则,\(i-1\) 的下标\(j >= i-k\), 把排列的前 \(j\) 个数字离散化为都由\(1\) ~ \(j\) 组合之后,这些数字组成的排列一定是以 \(j\) 结尾,满足题目要求的排列,共有\(dp[j]\)个,因为后面的数字少于 \(k\)个,不可能满足题目要求。\(dp[j]\) 是离散化之后的结果,离散化之前的结果共有\(dp[j]*C(i-2,j-1)*(i-j-1)!=dp[j]*\frac{(i-2)!}{(j-1)!}\)个。可以理解为:先在剩下的 \(i-2\) 个数当中取 \(j-1\) 个排在下标为$ 1~j-1的$位置,下标 \(j\) 之后到最后一个元素之前的位置随意排列)。
所以,两种情况加起来就是:
\(dp[i]=(i-k-1)*(i-2)!+\sum_{j=i-k}^{i-1}dp[j]*\frac{(i-2)!}{(j-1)!}\)。
但是这样直接计算要 \(O(n^2)\)。
提取一下\((i-2)!\),变成:
\(dp[i]=(i-k-1)*(i-2)!+(i-2)!*\sum_{j=i-k}^{i-1}\frac{dp[j]}{(j-1)!}\)
\(= (i-2)!*[(i-k-1)+\sum_{j=i-k}^{i-1}\frac{dp[j]}{(j-1)!}]\)
后面一项 \(\frac{dp[j]}{(j-1)!}\) 就可以利用前缀和求出。阶乘的乘除可以利用逆元求出。直接算就是O(n)。
\(dp[n]\)是以 \(n\) 结尾的排列个数。我们把 \(n\) 排在不同的位置 \(h\),把\(n\)下标之前的数离散化到\(1\) ~ \(h-1\),跟上面的一样,所以最终答案为:
\(\sum_{h=1}^{n}dp[h]*\frac{(n-1)!}{(h-1)!}\)。
总复杂度:\(O(n)\)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000010;
ll inv[maxn],fac[maxn],dp[maxn],sum[maxn];
const int mod =1e9+7;
ll qpower(ll a,ll b){
ll res = 1;
while(b)
{
if(b&1)res = res*a%mod;
b>>=1;
a= a*a%mod;
}
return res;
}
int main(int argc, char const *argv[]) {
ll n,k;
ll ans = 0;
cin>>n>>k;
if(k+1>=n){
printf("0\n");
exit(0);
}
fac[0] = 1;
for (int i = 1; i <=n; i++) {
fac[i] = (fac[i-1] * i) %mod;
}
inv[n] = qpower(fac[n],mod-2);
for(int i=n-1;i>=0;i--){
inv[i] = inv[i+1] *(i+1);
inv[i] %= mod;
}
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i=k+2;i<=n;i++){
dp[i] = (i-k-1 + (sum[i-1] - sum[i-k-1] +mod)%mod)%mod;
dp[i] = (dp[i] * fac[i-2]) % mod;
sum[i] = sum[i-1] + (dp[i] * inv[i-1])%mod;
sum[i] %= mod;
ans += (((dp[i] * fac[n-1]) % mod) * inv[i-1])%mod;
ans %= mod;
}
cout<<ans<<endl;
return 0;
}
ADDITION:
当然也可以把不符合题目条件的先算出来,然后用 \(n!\)减去不符合条件的个数,即为答案。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1000005;
ll inv[maxn],fac[maxn],dp[maxn],sum[maxn];
const int mod =1e9+7;
ll qpower(ll a,ll b){
ll res = 1;
while(b)
{
if(b&1)res = res*a%mod;
b>>=1;
a= a*a%mod;
}
return res;
}
int main(int argc, char const *argv[]) {
ll n,k;
cin>>n>>k;
if(k+1>=n)
{
printf("0\n");
exit(0);
}
fac[0] = 1;
for(int i=1;i<=n;i++){
fac[i] = fac[i-1]*i%mod;
}
inv[n] = qpower(fac[n],mod-2);
for(int i=n-1;i>=0;i--){
inv[i] = inv[i+1] * (i+1) %mod;
}
dp[1] = sum[1] = 1;
ll ans = fac[n-1];
for(int i=2;i<=n;i++){
dp[i] = (sum[i-1] - sum[max(0LL,i-k-1)]) *fac[i-2] %mod;
sum[i] = (sum[i-1] + dp[i] * inv[i-1]) % mod;
ans = (ans + dp[i] * fac[n-1] %mod * inv[i-1])%mod;
}
cout<<(fac[n]-ans+mod)%mod<<endl;
return 0;
}
Codeforces Round #445 Div. 1 C Maximum Element (dp + 组合数学)的更多相关文章
- Codeforces Round #174 (Div. 1) B. Cow Program(dp + 记忆化)
题目链接:http://codeforces.com/contest/283/problem/B 思路: dp[now][flag]表示现在在位置now,flag表示是接下来要做的步骤,然后根据题意记 ...
- Codeforces Round #221 (Div. 1) B. Maximum Submatrix 2 dp排序
B. Maximum Submatrix 2 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset ...
- Codeforces Round #276 (Div. 1) B. Maximum Value 筛倍数
B. Maximum Value Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/484/prob ...
- Codeforces Round #508 (Div. 2) E. Maximum Matching(欧拉路径)
E. Maximum Matching 题目链接:https://codeforces.com/contest/1038/problem/E 题意: 给出n个项链,每条项链左边和右边都有一种颜色(范 ...
- Codeforces Round #172 (Div. 2) D. Maximum Xor Secondary 单调栈应用
http://codeforces.com/contest/281/problem/D 要求找出一个区间,使得区间内第一大的数和第二大的数异或值最大. 首先维护一个单调递减的栈,对于每个新元素a[i] ...
- Codeforces Round #276 (Div. 1)B. Maximum Value 筛法
D. Maximum Value You are given a sequence a consisting of n integers. Find the maximum possible ...
- Codeforces Round #599 (Div. 2) A. Maximum Square 水题
A. Maximum Square Ujan decided to make a new wooden roof for the house. He has
- Codeforces Round #555 (Div. 3) F. Maximum Balanced Circle
F. Maximum Balanced Circle 题目链接 题意 给出\(n\)个数,现在要从中选出最多的数\(b_i,b_{i+1},\cdots,b_k\),将这些数连成一个环,要求两两相邻的 ...
- Codeforces Round #568 (Div. 2) D. Extra Element
链接: https://codeforces.com/contest/1185/problem/D 题意: A sequence a1,a2,-,ak is called an arithmetic ...
随机推荐
- vue踩坑-Error: listen EADDRNOTAVAIL 192.168.1.122:8081
每天上班,重启电脑,按照下面的步骤,打开vue的项目,开始编写代码,但是,今天一如往常一般操作:1:cd /项目名称 下面就是运行项目了,cd /项目名称,我的文件放在D盘,所以先进入d盘,再进入项目 ...
- Mybatis mapper.xml文件头文件备份
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-/ ...
- SpringBoot @PathVariable 和 @requestParam区别
1.若获取的入参的 参数 是下面这种形式 就使用 @requestParam 去获取 参数‘1’ /user?id=1 // url:xxx/user?id=1 @RequestMapping(&qu ...
- 【Codeforces Round #459 (Div. 2) C】The Monster
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 左括号看成1 右括号看成-1 设置l,r表示前i个数的和的上下界 遇到 左括号 l和r同时加1 遇到右括号 同时减1 遇到问号 因为 ...
- CSUOJ 1603 Scheduling the final examination
1603: Scheduling the final examination Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 49 Solved: 1 ...
- WEB开发中一些常见的攻击方式及简单的防御方法
WEB开发中一些常见的攻击方式及简单的防御方法 转载:http://blog.csdn.net/seven__________7/article/details/70896913
- OCP-1Z0-051-题目解析-第27题
27. Which two statements are true regarding tables? (Choose two.) A. A table name can be of any len ...
- JSONArray和JSONObject的简单使用
一.为什么要使用JSONArray和JSONObject 1.后台 -->前台 能够把java对象和集合转化成json字符串格式,这样在前台的ajax方法中能够直接转化成json对象使用 ,从后 ...
- js---10时间类
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...
- Kinect 开发 —— 骨骼追踪(下)
Kinect 连线游戏 在纸上将一些列数字(用一个圆点表示)从小到大用线连起来.游戏逻辑很简单,只不过我们在这里要实现的是动动手将这些点连起来,而不是用笔或者鼠标. 在开始写代码之前,需要明确定义我们 ...