cf----C. Permutation Partitions题解

昨天晚上做了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;
}

稍加解释,希望像我一样搜题解搜不到的人,看到后,豁然开朗

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值