QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#761189 | #3040. Container | Hkueen | WA | 2ms | 10108kb | C++14 | 4.8kb | 2024-11-18 21:23:38 | 2024-11-18 21:23:40 |
Judging History
answer
/*
考场上直接跳掉了
因为只剩20分钟,选择了更好骗分的t4
没想到前两题给我挂了140pts
我们如果让所有蓝色弹珠归位,就满足题目限制
所以可以只看蓝色弹珠
那么有用的操作其实一共就三种
1.[BR]<->[RB],花费C+3的代价,使蓝色弹珠移动一格
2.[BRR]<->[RRB],花费C+4的代价,使蓝色弹珠移动两格
3.[BBR]<->[RBB],花费C+5的代价,使蓝色弹珠移动两格,并越过一个蓝色弹珠
不难发现,我们一定不会越过一个最初与自己奇偶性相同的弹珠,这样一定不优;如果要移动大于1步,那么一定会选择操作2/3。
那么我们可以很方便地刻画代价:
将一个蓝色弹珠移动d步的代价就是(d>>1)*(C+4)+(d&1)*(C+3)+num,其中num表示途中越过的蓝色弹珠数量
那么特殊性质B的分就能直接骗到手
(特殊性质B:保证S和T中所有蓝色弹珠的下标都具有相同的奇偶性。)
我们直接按照顺序,一个萝卜一个坑地将S中的蓝色弹珠分配给T就好了
将所有 向右移动/向左移动/不动 的点 按照起点坐标从大到小操作/按照起点坐标从小到大操作/不管 就好了
ok,接着我们考虑更一般的情况
有结论:将S中的蓝色弹珠按照终点位置的奇偶性分成两个集合,这两个集合内部的点是按顺序分配的
证明:总代价为Σ(d>>1)*(C+4)+(d&1)*(C+3)+num。终点的奇偶性相同,那么Σ(d&1)*(C+3)相同。而按顺序分配,(d>>1)*(C+4)和num一定都是不劣的
那么,只需要把蓝色弹珠分组就好了
设f[i][j]表示考虑前i个蓝色弹珠,有j个被分到第1个集合(终点为奇数)的最小代价
转移:
f[i][j]=min(f[i-1][j-1]+val1,f[i-1][j]+val2)
val的计算比较容易,因为f[i][j]这个状态已经框定了i最终可能的两个终点
我们直接数与i不同的那个集合有几个数已经被分到i的后面就好了
预处理的话,可以做到O(n^2)
好吧,我多了个log
*/
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
constexpr int N=1010,INF=5e8;
char s[N],t[N];
vector<pair<int,int> >out;
int c;
void move(int st,int ed){
//printf("move(%d,%d)\n",st,ed);
if(st>ed){
while(st-ed>1){
if(s[st]==s[st-2])st-=2;
else{
//ans+=c+4;
out.emplace_back(st-2,st);
swap(s[st-2],s[st]);
st-=2;
}
}
if(st>ed){
//ans+=c+3;
out.emplace_back(ed,st);
swap(s[ed],s[st]);
}
}
else{
while(ed-st>1){
if(s[st]==s[st+2])st+=2;
else{
//ans+=c+4;
out.emplace_back(st,st+2);
swap(s[st],s[st+2]);
st+=2;
}
}
if(st<ed){
//ans+=c+3;
out.emplace_back(st,ed);
swap(s[st],s[ed]);
}
}
}
int calc(int i,int j){
int d=abs(i-j);
return (d>>1)*(c+4)+(d&1)*(c+3);
}
int n,i,j,val1[N][N],val2[N][N],f[N][N],g[N][N];
vector<int>v[2];
vector<pair<int,pair<int,int> > >ned;
bool cmp(pair<int,pair<int,int> >x,pair<int,pair<int,int> >y){
return x.fi==y.fi?x.fi==0?x.se.fi>y.se.fi:x.se.fi<y.se.fi:x.fi<y.fi;
}
vector<int>all;
void str(int i,int j){
if(!i)return;
//fprintf(stderr,"str(%d,%d)\n",i,j);
if(g[i][j])ned.push_back({all[i-1]>v[1][i-j-1],{all[i-1],v[1][i-j-1]}});
else ned.push_back({all[i-1]>v[0][j-1],{all[i-1],v[0][j-1]}});
str(i-1,j-(!g[i][j]));
}
int main(){
scanf("%*d%d%d%s%s",&n,&c,s+1,t+1);
for(i=1;i<=n;++i)if(t[i]=='B')v[i&1].emplace_back(i);
for(i=1;i<=n;++i)if(s[i]=='B')all.emplace_back(i);
int len1=v[0].size(),len2=v[1].size();
//fprintf(stderr,"len1=%d len2=%d\n",len1,len2);
memset(f,63,sizeof f);
f[0][0]=0;
for(i=1;i<=len1+len2;++i){
for(j=0;j<=i;++j){//第1个集合有j个数(第二个集合i-j个数)
/*val1[i][j]:第1个集合有j个数,第二个集合i-j个数,i放第1个集合*/
/*val2[i][j]:第1个集合有j个数,第二个集合i-j个数,i放第2个集合*/
if(j>len1||i-j>len2)continue;
//fprintf(stderr,"i=%d j=%d\n",i,j);
val1[i][j]=(j?max(0,(i-j-1)-(int)(lower_bound(v[1].begin(),v[1].end(),v[0][j-1]+1)-v[1].begin())+1):INF);
//fprintf(stderr,"ok1\n");
val2[i][j]=(i-j?max(0,(j-1)-(int)(lower_bound(v[0].begin(),v[0].end(),v[1][i-j-1]+1)-v[0].begin())+1):INF);
//fprintf(stderr,"ok2\n");
f[i][j]=min(f[i-1][j-1]+val1[i][j]+(j?calc(all[i-1],v[0][j-1]):INF),f[i-1][j]+val2[i][j]+(i-j?calc(all[i-1],v[1][i-j-1]):INF));
//fprintf(stderr,"ok3\n");
if(f[i][j]==f[i-1][j-1]+val1[i][j]+(j?calc(all[i-1],v[0][j-1]):INF))g[i][j]=0;
else g[i][j]=1;
//fprintf(stderr,"f[%d][%d]=%d\n",i,j,f[i][j]);
}
}
int mn=0;
for(j=1;j<=len1+len2;++j)if(f[len1+len2][j]<f[len1+len2][mn])mn=j;
str(len1+len2,mn);
sort(ned.begin(),ned.end(),cmp);
for(auto x:ned)move(x.se.fi,x.se.se);
printf("%d\n",(int)out.size());
for(auto [x,y]:out)printf("%d %d\n",x,y);
return 0;
}
詳細信息
Test #1:
score: 0
Wrong Answer
time: 2ms
memory: 10108kb
input:
5 2 11221 21112
output:
0
result:
wrong answer invalid plan.