ICPC 2022 KM B
题目链接
首先是判断每个子集是否覆盖了整个矩形,离散化后暴力做是 \(O(2^nT*400)\),会TLE。当时队友想了一个挺巧妙的容斥的做法,但写起来比较复杂。其实发现就是一个01取并集的过程,可以直接bitset优化掉32倍的常数就ok了!
然后是状态转移,其实是比较经典的问题:有向图第一次走到合法的点的期望。但当时沿用了从起点开始,记录概率和期望的思路,结果碰到了一些麻烦就没调出来(后来冷静想了一下应该还是可以做的)
但从终点(合法点)往前考虑就会方便很多:直接DP考虑每个点出发的期望,从后往前DP即可!
就是要跳出从起点往后做的思维,考虑起点第一次到合法状态的期望这个问题:发现起点的问题可以转化为第一步到达的点的问题,所以就直接把状态设计为该点出发第一次到合法状态的期望!
#include<bits/stdc++.h>
using namespace std;
const int N=25,P=998244353;
int fpw(int a,int x){
int s=1;
for(;x;x>>=1,a=1ll*a*a%P) if(x&1) s=1ll*s*a%P;
return s;
}
void discretize(int& mx,int* a,int* b,int n){
vector<int>h;
h.push_back(0);
h.push_back(mx);
for(int i=1;i<=n;i++){
//a[i]++;
a[i]=min(a[i],mx);
b[i]=min(b[i],mx);
h.push_back(a[i]);
h.push_back(b[i]);
}
sort(h.begin(),h.end());
vector<int>:: iterator it=unique(h.begin(),h.end());
h.erase(it,h.end());
//for(int i=0;i<h.size();i++) cout<<h[i]<<" "; puts("");
for(int i=1;i<=n;i++){
a[i]=lower_bound(h.begin(),h.end(),a[i])-h.begin()+1;
b[i]=lower_bound(h.begin(),h.end(),b[i])-h.begin();
}
mx=h.size()-1;
}
int n,W,H,x[N],y[N],x2[N],y2[N],iv[N];
bitset<512>ss[N],sg[1<<10];
int f[1<<10];
void work(){
cin>>n>>W>>H;
for(int i=1;i<=n;i++){
scanf("%d%d%d%d",&x[i],&y[i],&x2[i],&y2[i]);
iv[i]=fpw(i,P-2);
}
discretize(W,x,x2,n);
discretize(H,y,y2,n);
//return;
/*cout<<W<<" "<<H<<endl;
for(int i=1;i<=n;i++)
printf("%d %d %d %d\n",x[i],x2[i],y[i],y2[i]);
*/
//return;
for(int i=1;i<=n;i++){
ss[i].reset();
for(int j=x[i];j<=x2[i];j++){
for(int k=y[i];k<=y2[i];k++){
ss[i][(j-1)*H+k-1]=1;
}
}
}
for(int i=0;i<(1<<n);i++) sg[i].reset();
for(int i=0;i<(1<<n);i++){
for(int j=1;j<=n;j++) if(!(i&(1<<(j-1)))){
int t=i+(1<<(j-1));
if(!sg[t].count()) sg[t]=sg[i]|ss[j];
}
}
if(sg[(1<<n)-1].count()!=W*H){
puts("-1");
return;
}
for(int i=(1<<n)-1;~i;i--){
if(sg[i].count()==W*H){
f[i]=0;
continue;
}
int t=0,s=0;
for(int j=1;j<=n;j++){
if(i&(1<<(j-1))) t++;
else (s+=f[i+(1<<(j-1))])%=P;
}
f[i]=1ll*(s+n)*iv[n-t]%P;
}
cout<<f[0]<<endl;
}
int main()
{
//srand(time(0));
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
int T; cin>>T; while(T--) work();
return 0;
}
浙公网安备 33010602011771号