涂色问题 乘法原理(2024CCPC 山东省赛 C)

//*下午打得脑子连着眼睛一起疼

很多很基础的题目都没有做出来,规律题也找得很慢。比如下面这题,一定要多做,下次看到就直接写。


原题链接:https://codeforces.com/group/w6iGs8kreW/contest/555584/problem/C

C. Colorful Segments 2

time limit per test

2 seconds

memory limit per test

1024 megabytes

Consider nn segments on the number axis, where the left endpoint of the ii-th segment is lili and the right endpoint is riri. You need to paint each segment into one of the kk colors, so that for any two segments with the same color they do not overlap.

Calculate the number of ways to color the segments.

We say segment ii overlaps with segment jj, if there exists a real number xx satisfying both li≤x≤rili≤x≤ri and lj≤x≤rjlj≤x≤rj.

We say two ways of coloring the segments are different, if there exists one segment which has different colors in the two ways.

Input

There are multiple test cases. The first line of the input contains an integer TT indicating the number of test cases. For each test case:

The first line contains two integers nn and kk (1≤n≤5×1051≤n≤5×105, 1≤k≤1091≤k≤109) indicating the number of segments and the number of colors.

For the following nn lines, the ii-th line contains two integers lili and riri (1≤li≤ri≤1091≤li≤ri≤109) indicating the left and right endpoints of the ii-th segment.

It's guaranteed that the sum of nn of all test cases will not exceed 5×1055×105.

Output

For each test case output one line containing one integer indicating the answer. As the answer might be large, output it modulo 998244353998244353.


大致题意  :  一共给k个颜色,有n个区间。规定两个重叠区间不能染相同颜色。问有多少种染色方法。 其实想很好想,就是 排序 遍历考虑出每个区间的颜色种数(只受其前面区间的限制) 乘法原理相乘 即可。

WA:一开始是把每个点的右端点排序,然后数这个区间与前面多少区间有重叠,如果与m个重叠,那可填颜色数就是k-m。但是!这样不对,例如:

(搞笑啊)

一号和二号都能填k种,但三号不止能填k-2种(当1 2填的颜色一样时,3能填k-1种)。

so右端点排序不对!

正解:左端点排序,可以用一个优先队列来储存,每段的初始颜色都是k-1(与上段不同),如果与上段没有重合,k++。否则break。

看代码:

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
#define int long long 
 
int t;
int n,k;
const int mod=998244353;
 
struct O{
	int l,r;
}a[1000010];
vector<int>q;
 
bool sorrt(struct O i,struct O j){
	return i.l<j.l;
}
 
void solve(int n,int k){
	priority_queue<int,vector<int>,greater<int>>q;
	for(int i=1;i<=n;i++){
		cin>>a[i].l>>a[i].r;
	}
	sort(a+1,a+n+1,sorrt);
	int ans=k%mod;
	k--;
	q.push(a[1].r);
	for(int i=2;i<=n;i++){
		while(!q.empty()&&q.top()<a[i].l){
			k++;
			q.pop();
		}
		ans=(ans*k)%mod;
		k--;
		if(k<0)k=0;
		q.push(a[i].r);
		
	}
	cout<<ans<<endl;
}
 
signed main()
{
	cin>>t;
	while(t--){
		cin>>n>>k;
		solve(n,k);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值