题解:P10561 [ICPC 2024 Xi'an I] Smart Quality Inspector
题解:P10561 [ICPC 2024 Xi'an I] Smart Quality Inspector
思路
注意到 __builtin_popcount(i) 来快速计算)。把当前数填入之后,它对答案的贡献就是 sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];\
二维前缀和查询公式:x=sum[p][r-1]-sum[p][p-1]-sum[l][r-1]+sum[l][p-1];。\
那么,转移方程就是:
注意点
- 由于
(i)_2 高位表示左边,低位表示右边,我们还要在找到L 和R 后翻转位置,将L 赋值为n-L+1 ,R 和p 同理。 - 在枚举点
p 时,如果当前状态没有填入点p ,需直接跳过该状态。
:::success[AC Code]
时间复杂度
#include<bits/stdc++.h>
using namespace std;
int n,k,m,sum[25][25],f[(1<<20)+1],ans=2e9;
int main(){
cin>>n>>k>>m;
for(int i=1;i<=m;++i){
int l,r;
cin>>l>>r;
++sum[l][r];
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]; // 二维前缀和计算
}
}
for(int i=1;i<(1<<n);++i){
int tot=__builtin_popcount(i);
if(tot>k)continue; // 填入数量过多,跳过
f[i]=INT_MAX; // 一定要初始化成极大值!
for(int j=1;j<=n;++j){
if(!((i>>j-1)&1))continue;
int l,r;
for(l=j+1;l<=n;++l){
if((i>>l-1)&1)break;
}
for(r=j-1;r>=1;--r){
if((i>>r-1)&1)break;
}
l=n+1-l;
r=n+1-r;
int p=n+1-j;
int x=sum[p][r-1]-sum[p][p-1]-sum[l][r-1]+sum[l][p-1]; // 合法区间个数
f[i]=min(f[i],f[i-(1<<j-1)]+x*(k-tot+1));
}
}
for(int i=1;i<(1<<n);++i){
if(__builtin_popcount(i)==k){ // 计算答案
ans=min(ans,f[i]);
}
}
cout<<ans;
return 0;
}
:::