[CCPC 2024 Shandong I] 多彩的线段 2题解
题目描述
考虑数轴上的 n 条线段,其中第 i 条线段的左端点为 li,右端点为 ri。您需要将每条线段涂上 k 种颜色中的一种,使得任意两条具有相同颜色的线段都没有重合。
求给线段涂色的方案数。
称第 i 条线段和第 j 条线段有重合,若存在一个实数 x 同时满足 li≤x≤ri 且 lj≤x≤rj。
称两种涂色方案是不同的,若存在一条线段在两种方案中被涂上了不同的颜色。
输入格式
有多组测试数据。第一行输入一个整数 T 表示测试数据组数。对于每组测试数据:
第一行输入两个整数 n 和 k(1≤n≤5×105,1≤k≤109)表示线段的数量和颜色的数量。
对于接下来的 n 行,第 i 行输入两个整数 li 和 ri(1≤li≤ri≤109)表示第 i 条线段的左右端点。
保证所有数据 n 之和不超过 5×105。
输出格式
每组数据输出一行一个整数表示答案。由于答案可能很大,请将答案对 998244353 取模后输出。
输入输出样例
输入 #1复制
2 4 3 4 7 3 4 5 8 1 3 2 1000 100 200 300 400
输出 #1复制
24 1000000
说明/提示
令 ci 表示第 i 条线段的颜色。
对于第一组样例数据,一种合法的涂色方案是令 c1=1,c2=3,c3=3 以及 c4=1。因为第 1 条和第 4 条线段没有重合,第 2 条和第 3 条线段也没有重合。
然而, c1=1,c2=2,c3=1 以及 c4=3 不是一种合法的方案。因为第 1 条和第 3 条线段互相重合,不能有一样的颜色。
思路
离散化,再用差分维护即可。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long t,n,k,b[1000006],c[10000006],mod=998244353,qd=0,cb,lk=1;
struct one{
long long l,r;
}a[500005];
bool cmp5(one a1,one b1){
return a1.l<b1.l;
}
map<long long,long long> mp;
int main(){
cin>>t;
while(t--){
cin>>n>>k;
mp.clear();
b[0]=0;
for(int i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;
b[++b[0]]=a[i].l;
b[++b[0]]=a[i].r;
}
sort(b+1,b+b[0]+1);
qd=0;
for(int i=1;i<=b[0];i++){
if(i==1||b[i]!=b[i-1]){
qd+=2;
mp[b[i]]=qd;
}
}
sort(a+1,a+n+1,cmp5);
for(int i=1;i<=n;i++){
a[i].l=mp[a[i].l];
a[i].r=mp[a[i].r];
}
for(int i=1;i<=qd+1;i++){
c[i]=0;
}
cb=k;
lk=1;
for(int i=1;i<=n;i++){
//cout<<a[i].l<<" "<<a[i].r<<endl;
for(int j=a[i-1].l+1;j<=a[i].l;j++){
cb+=c[j];
}
if(cb<=0){
lk=0;
break;
}
//cout<<cb<<endl;
lk=(lk*cb)%mod;
cb--;
c[a[i].l]--;
c[a[i].r+1]++;
}
cout<<lk<<endl;
}
return 0;
}

浙公网安备 33010602011771号