题目:http://codeforces.com/contest/733/problem/C
题意:
给你n个数,a1,a2,a3,…an,再给你m个数b1,b2,b3,…bm,问你a序列能否通过合并变成b序列。合并的条件为只能相邻的数合并,ai与ai+1能合并的条件为ai> ai+1或ai< ai+1。合并出来的值为ai+ai+1。然后通过新序列合并下去问你能不能达到b序列?能达到的话输出是如何合并的,不能的话输出NO。
分析:
自己的做法是先分块,看是否可以把一段a分成b。这求一下前缀和然后二分即可。
如果可以,那么接下来合并。从左到右扫描,如果a[j]==a[j+1],那么继续看下一个
否则就可以合并这两个,并且把前面相等的都合并(因为当前两个合并后一定大于前面相等的)
上面就是我一开始的做法,悲剧的是WA在了106个样例上QAQ
存在这样一种情况
3 2 5
按照我的做法,3!=2,那么合并,结果是5 5,剩下的就不能合并了。
修正的做法是判断一下3 2合并后是否等于下一个元素,如果等于,那跳过,先不合并。
否则就可以合并。
自己的做法稍微麻烦了点。因为合并的过程中,应该从最大的开始往左往右合并,这样如果存在可行方案,一定有解。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,char>pii;
const int INF=0x3f3f3f3f;
const int N=1e6+9;
int s[N];
int a[N],b[N],n,m,x[N],pre[N];
pii ans[N];
int main() {
freopen("f.txt","r",stdin);
scanf("%d",&n);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
}
scanf("%d",&m);
ll sum=0;
for(int i=1; i<=m; i++) {
scanf("%d",&x[i]);
sum+=x[i];
}
if(sum!=s[n]) {
puts("NO");
return 0;
}
sum=0;
int cnt=0;
for(int i=1; i<=m; i++) {
sum+=x[i];
int g=lower_bound(s+1,s+1+n,sum)-s;
pre[i]=g;
if(s[pre[i]]-s[pre[i-1]]!=x[i]) {
puts("NO");
return 0;
}
int num=0,tsum=0;
for(int j=pre[i-1]+1; j<pre[i]; j++) {
tsum+=a[j];
if(a[j]==a[j+1])
num++;
else if(j+2<=pre[i]&&tsum+a[j+1]==a[j+2]) //不加这个判断下面的样例过不了
num++;
else if(a[j]<a[j+1]) {
ans[cnt++]=make_pair(i+1+num,'L');
while(num) {
ans[cnt++]=make_pair(i+num,'L');
num--;
}
a[j+1]+=tsum;
tsum=num=0;
} else if(a[j]>a[j+1]) {
ans[cnt++]=make_pair(i+num,'R');
while(num) {
ans[cnt++]=make_pair(i+num,'L');
num--;
}
a[j+1]+=tsum;
tsum=num=0;
}
}
if(num>0) {
puts("NO");
return 0;
}
}
puts("YES");
for(int i=0; i<cnt; i++)printf("%d %c\n",ans[i].first,ans[i].second);
return 0;
}
/*
Input
3
3 2 5
1
10
Output
YES
3 L
2 L
*/