QOJ.ac

QOJ

ID题目提交者结果用时内存语言文件大小提交时间测评时间
#761189#3040. ContainerHkueenWA 2ms10108kbC++144.8kb2024-11-18 21:23:382024-11-18 21:23:40

Judging History

This is the latest submission verdict.

  • [2024-11-18 21:23:40]
  • Judged
  • Verdict: WA
  • Time: 2ms
  • Memory: 10108kb
  • [2024-11-18 21:23:38]
  • Submitted

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.