原题请看这里
中国的电影院在关闭六个月后将重新开放,以帮助减缓冠状病毒的传播。
阿波罗的电影院有 n n n排座位,每排有 m m m个座位
行。我们将第 x x x行和第 y y y列上的座位表示为一对数字 ( x , y ) (x,y) (x,y)。根据该政策,电影院中的人们需要保持社交距离。因此,两个人不能坐在相邻的两个座位上。
如果两个席位 ( x 1 , y 1 ) ( x 2 , y 2 ) (x_1,y_1)(x_2,y_2) (x1,y1)(x2,y2)具有相同的边缘,则认为它们是相邻的,
即 ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ = 1 | x_1-x_2 | + | y_1-y_2 | = 1 ∣x1−x2∣+∣y1−y2∣=1
人们将来到票房一张一张地买票,并允许他们自己选择座位。人们可以选择任何有效的座位。如果不是由其他人选择并且不与其他人相邻的座位,则该座位有效。如果没有有效的座位,电影院收银员将停止出售门票。作为电影院的老板,阿波罗想知道最坏情况下可以出售的最低票数。我们可以假设有足够的人来购买门票(即电影院收银员将继续出售门票,直到没有有效的座位为止)。
输入的第一行给出测试用例的数量 T ( 1 ≤ T ≤ 1000 ) \mathbf {T}(1 \leq \mathbf {T} \leq 1000) T(1≤T≤1000)。 T \mathbf {T} T组测试用例如下。
每个测试用例由一行包含两个整数 n ( 1 ≤ n ≤ 1000 ) n(1 \le n \le 1000) n(1≤n≤1000)和 m ( 1 ≤ m ≤ 15 ) m(1 \le m \le 15) m(1≤m≤15)组成,分别表示行数和列数。
对于每个测试用例,输出一行包含 C a s e Case Case # x x x: y y y,其中 x x x是测试用例编号(从 1 1 1开始), y y y是在最坏情况下可以出售的最小票数。 然后,再打印 n n n行,每行 m m m个字符,表示只能卖 y y y张电影票的情况。 “ *”表示已选择座位“.” 表示未选择座位。
如果有多个有效答案,则可以输出其中任何一个。
3
3 3
4 5
1 5
Case #1: 3
*.*
...
.*.
Case #2: 6
..*.*
*....
...*.
.*..*
Case #3: 2
.*.*.
状压 d p dp dp 看到m的取值范围就想到状压了
首先我们考虑一般的状压怎么写:0表示这个位子没有人,1表示这个位子没有人。
可是我们脑袋一拍可以知道这两种肯定不够,如果是求最多,那么两种就足够了。
一个位子可以贡献四个位子不能坐人,如果两个位子的贡献重合了,那肯定是不划算的,所以我们还要存这个位子周围是否有人,于是我们重新定义状压的写法:
这时我们的任务已经完成一大半了:一个三进制的状压。但是一看数据范围,我们发现 3 15 ∗ 1000 3^{15}*1000 315∗1000直接炸了…更何况还有 1000 1000 1000组数据。
于是接下来我们的任务就是:怎样压缩数据。
如果有刷题广的人做过这题:方格取数,就会发现:这题的情况和本题类似,都需要压缩数据。在 d p dp dp数组中存的状态是否都是有用的呢?显然不是,比如说如果两个2相邻,那么就不用考虑了,所以,我们需要进行一个操作:离散化。
在同一行内有许多不合法的情况可以筛除:
所以我们只要预处理每一个m的不合法情况进行剔除,就不会爆了。
#include
#define ll long long
using namespace std;
struct node{
int first;
int second;
node(){}
node(int _f,int _s){first=_f,second=_s;}
bool operator < (const node &n1)const{
return first<n1.first;
}
};
const int MAXM=16;
const int MAXX=1005;
const int MAXN=6600;
const int MAX=13e6+5;
int qm[MAXX],sta[MAXN],id[MAX],dp[MAXX][MAXN];
int pre[MAXX][MAXN],num2[MAXN],num0[MAXN],ans[MAXN];
int tot,t,n,m;
vector<node> vec[MAXN];
vector<int> nxt[MAXN],sol[MAXN];
void dfs(int pos,int now,int mm){
if(pos==mm){
if(pos>=2&&(now%3==1)&&(now/3%3==1)&&(pos-2<0||now/9%3!=2))return;
id[now]=tot;sta[tot++]=now;return;
}if(!pos){
dfs(pos+1,now*3,mm);
dfs(pos+1,now*3+1,mm);
dfs(pos+1,now*3+2,mm);
return;
}if(now%3^1){dfs(pos+1,now*3+1,mm);return;}
dfs(pos+1,now*3+2,mm);
if(!(pos>=2&&(now%3==1)&&now/3%3==1&&(pos-2<0||now/9%3!=2))){
dfs(pos+1,now*3,mm);
dfs(pos+1,now*3+1,mm);
}
}int get2(int x){
int ret=0;
while(x){ret+=(x%3==2);x/=3;}
return ret;
}int get0(int x,int mm){
int ret=0;
for(int i=0;i<mm;++i){ret+=(x%3==0);x/=3;}
return ret;
}void search(vector<int> &res,int a[],int mm,int now,int pos){
if(pos>=mm){res.push_back(now);return;}
if(a[pos]==2) search(res,a,mm,now*3+1,pos+1);
else if(!a[pos]){
if(pos+1<mm) search(res,a,mm,(now*3+2)*3+1,pos+2);
else search(res,a,mm,now*3+2,pos+1);
}else{
if(pos+1<mm){
if(!a[pos+1]) search(res,a,mm,now*3+1,pos+1);
else if(a[pos+1]==2){
search(res,a,mm,now*3,pos+1);
search(res,a,mm,now*3+2,pos+1);
}else{
if(pos+2>=mm||a[pos+2]==2){
search(res,a,mm,(now*3+2)*3+1,pos+2);
search(res,a,mm,(now*3+1)*3+2,pos+2);
}else if(!a[pos+2]){
search(res,a,mm,now*9+1,pos+2);
search(res,a,mm,(now*3+2)*3+1,pos+2);
}else if(pos+3>=mm||a[pos+3]==2){
search(res,a,mm,(now*3+2)*3+1,pos+2);
search(res,a,mm,(now*9+1)*3+2,pos+3);
search(res,a,mm,((now*3+1)*3+2)*3+1,pos+3);
}
}
}else{
search(res,a,mm,now*3,pos+1);
search(res,a,mm,now*3+2,pos+1);
}
}
}
bool check(int x,int mm){
int a[MAXN];
for(int i=0;i<mm;++i){a[i]=x%3;x/=3;}
for(int i=0;i<mm;++i)
if(a[i]==1&&(!i||a[i-1]!=2)&&(i==mm-1||a[i+1]!=2))
return false;
return true;
}
int a[MAXN];
void solve(vector<node> query,int mm){
int qsize=query.size();
if(!qsize) return;
sort(query.begin(),query.end());
tot=0;
dfs(0,0,mm);
for(int i=0;i<tot;++i){
num2[i]=get2(sta[i]);
num0[i]=get0(sta[i],mm);
nxt[i].clear();
int ts=sta[i];
for(int j=mm-1;j>=0;--j){
a[j]=ts%3;
ts/=3;
}search(nxt[i],a,mm,0,0);
}memset(dp,-1,sizeof(dp));
for(int i=0;i<tot;++i)
if(check(sta[i],mm))
dp[1][i]=num2[i];
int qid=0;
for(int i=1;i<=MAXX-5;++i){
while(qid<qsize&&query[qid].first==i){
int qin=query[qid].second;
ans[qin]=i*mm;
sol[qin].clear();
int tmp=-1;
for(int j=0;j<tot;++j)
if(dp[i][j]!=-1&&ans[qin]>dp[i][j]+num0[j]){
tmp=j;
ans[qin]=dp[i][j]+num0[j];
}
sol[qin].push_back(sta[tmp]);
for(int j=i;j>1;j--){
tmp=pre[j][tmp];
sol[qin].push_back(sta[tmp]);
}qid++;
}if(qid==qsize) break;
for(int j=0;j<tot;++j){
if(dp[i][j]==-1) continue;
for(int k=0;k<nxt[j].size();++k){
int v=nxt[j][k];
int idd=id[v];
if(dp[i+1][idd]==-1||dp[i+1][idd]>dp[i][j]+num2[idd]){
dp[i+1][idd]=dp[i][j]+num2[idd];
pre[i+1][idd]=j;
}
}
}
}
}void print(vector<int> tor,int mm){
for(int i=tor.size()-1;i>=0;--i){
int v=tor[i];
for(int j=0;j<mm;++j){
if(v%3==2||(!i&&v%3==0)) printf("*");
else printf(".");
v/=3;
}puts("");
}
}int main(){
for(int i=1;i<MAXM;++i)
vec[i].clear();
scanf("%d",&t);
for(int i=0;i<t;++i){
scanf("%d%d",&n,&m);
vec[m].push_back(node(n,i));
qm[i]=m;
}for(int i=1;i<MAXM;++i)
solve(vec[i],i);
for(int Case=0;Case<t;++Case){
printf("Case #%d: %d\n",Case+1,ans[Case]);
print(sol[Case],qm[Case]);
}
}