昨天晚上做了Codeforces,被一题坑了很久,Permutation Partitions,排列分区,题意如下:添加链接描述
给定一个从1到n的整数的排列p1 p2…pn和一个整数k,使1≤k≤n。一个排列意味着从1到n的每一个数字在p中都只包含一次。
让我们把这个排列的所有分区考虑成k个不相交的段。在形式上,一个分区是一组段{[l1,r1],[l2,r2],…,[lk,rk]},这样:
1≤li≤ri≤n,其中1≤i≤k;对于所有1≤j≤n,存在一个段[li,ri],使得li≤j≤ri。如果一个段位于一个分区中,而另一个分区不位于该分区中,则两个分区是不同的。
我们计算一下划分值,定义为∑i=1kmaxli≤j≤ripj,对于k个不相交段的所有可能的排列分区。找出所有这些分区上可能的最大分区值,以及具有该值的分区的数目。由于第二个值可能非常大,所以当除以998244353时,应该会发现它的余数。
输入
第一行包含两个整数,n和k(1≤k≤n≤200000)——给定排列的大小和一个分区中的段数。
第二行包含n个不同的整数p1,p2,…,pn(1≤pi≤n)——给定的排列。
输出
输出两个整数—k个不相交段的所有排列分区上的最大可能分区值,以及分区值等于最大可能分区值的分区数,即998244353。
请注意,您应该只找到第二个值modulo 998244353。
案例1:
输入
3 2
2 1 3
输出:
5 2
案例2:
输入
5 5
2 1 5 3 4
输出:
15 1
案例3:
输入
7 3
2 7 3 1 5 4 6
输出:
18 6
不废话,直接上代码
/*例1:cin>>7 3;cin>>2 7 3 1 5 4 6;
处理找到3个最大的数,5 6 7,mx=5+6+7=18
7和5之间相隔2个数,5和6之间相隔1个数,s=(2+1)*(1+1)=6;
cout<< mx<<s,输出18和6;*/
/*例2:cin>>7 3;cin>>1 7 2 3 4 5 6;
cout<<18<<4;
why?
与上例相同
处理找到3个最大的数,5 6 7,mx=5+6+7=18
7和5之间相隔3个数,5和6之间相隔0个数,s=(3+1)*(0+1)=4;
现在我问你输入7 3,输入7 1 2 5 3 4 6,输出什么?
*/
#include<iostream>
using namespace std;
#include<bits/stdc++.h>
const int M=998244353;
int n,m,a,lst,s;long long mx;
int main(){
scanf("%d%d",&n,&m);
s=1;
for(int i=1;i<=n;i++){
scanf("%d",&a);
if(a>n-m){
mx+=a;
if(lst){
cout<<s<<" "<<i-lst<<endl;
s=(long long)s*(i-lst)%M;
}
lst=i;
}
}
printf("%lld %d\n",mx,s);
return 0;
}
稍加解释,希望像我一样搜题解搜不到的人,看到后,豁然开朗