Codeforces Round #378 (Div. 2) C && Codeforces 733C (模拟)详解(两种写法)

来源:互联网 发布:淘宝店铺招牌是什么 编辑:程序博客网 时间:2024/06/09 18:27



C. Epidemic in Monstropolis
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

There was an epidemic in Monstropolis and all monsters became sick. To recover, all monsters lined up in queue for an appointment to the only doctor in the city.

Soon, monsters became hungry and began to eat each other.

One monster can eat other monster if its weight is strictly greater than the weight of the monster being eaten, and they stand in the queue next to each other. Monsters eat each other instantly. There are no monsters which are being eaten at the same moment. After the monster A eats the monster B, the weight of the monster A increases by the weight of the eaten monster B. In result of such eating the length of the queue decreases by one, all monsters after the eaten one step forward so that there is no empty places in the queue again. A monster can eat several monsters one after another. Initially there were n monsters in the queue, the i-th of which had weight ai.

For example, if weights are [1, 2, 2, 2, 1, 2] (in order of queue, monsters are numbered from 1 to 6 from left to right) then some of the options are:

  1. the first monster can't eat the second monster because a1 = 1 is not greater than a2 = 2;
  2. the second monster can't eat the third monster because a2 = 2 is not greater than a3 = 2;
  3. the second monster can't eat the fifth monster because they are not neighbors;
  4. the second monster can eat the first monster, the queue will be transformed to [3, 2, 2, 1, 2].

After some time, someone said a good joke and all monsters recovered. At that moment there were k (k ≤ n) monsters in the queue, thej-th of which had weight bj. Both sequences (a and b) contain the weights of the monsters in the order from the first to the last.

You are required to provide one of the possible orders of eating monsters which led to the current queue, or to determine that this could not happen. Assume that the doctor didn't make any appointments while monsters were eating each other.

Input

The first line contains single integer n (1 ≤ n ≤ 500) — the number of monsters in the initial queue.

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 106) — the initial weights of the monsters.

The third line contains single integer k (1 ≤ k ≤ n) — the number of monsters in the queue after the joke.

The fourth line contains k integers b1, b2, ..., bk (1 ≤ bj ≤ 5·108) — the weights of the monsters after the joke.

Monsters are listed in the order from the beginning of the queue to the end.

Output

In case if no actions could lead to the final queue, print "NO" (without quotes) in the only line.

Otherwise print "YES" (without quotes) in the first line. In the next n - k lines print actions in the chronological order. In each line printx — the index number of the monster in the current queue which eats and, separated by space, the symbol 'L' if the monster which stays the x-th in the queue eats the monster in front of him, or 'R' if the monster which stays the x-th in the queue eats the monster behind him. After each eating the queue is enumerated again.

When one monster eats another the queue decreases. If there are several answers, print any of them.

Examples
input
61 2 2 2 1 225 5
output
YES2 L1 R4 L3 L
input
51 2 3 4 5115
output
YES5 L4 L3 L2 L
input
51 1 1 3 332 1 6
output
NO
Note

In the first example, initially there were n = 6 monsters, their weights are [1, 2, 2, 2, 1, 2] (in order of queue from the first monster to the last monster). The final queue should be [5, 5]. The following sequence of eatings leads to the final queue:

  • the second monster eats the monster to the left (i.e. the first monster), queue becomes [3, 2, 2, 1, 2];
  • the first monster (note, it was the second on the previous step) eats the monster to the right (i.e. the second monster), queue becomes [5, 2, 1, 2];
  • the fourth monster eats the mosnter to the left (i.e. the third monster), queue becomes [5, 2, 3];
  • the finally, the third monster eats the monster to the left (i.e. the second monster), queue becomes [5, 5].

Note that for each step the output contains numbers of the monsters in their current order in the queue.

这个题,比赛的时候读过题,知道应该是个贪心,但是看到每次吃掉之后下标要重新改变之后,就觉得是个比较麻烦的模拟,当时就吓跑了哭,写的模拟题太少了,几乎没有。。模拟套路跟策略都不知道,还要多学习啊,之所以两种写法,是因为网上众多大牛都是用vector做的,十几分钟a掉,另一种就是跟CillyB学的,用一个结构体记录下标跟操作。。

题意:

给你n个数,a1,a2,a3,...an,再给你m个数b1,b2,b3,...bm,问你a序列能否通过合并变成b序列。合并的条件为只能相邻的数合并,aiai+1能合并的条件为ai>ai+1ai<ai+1。合并出来的值为ai+ai+1。然后通过新序列合并下去问你能不能达到b序列?能达到的话输出是如何合并的,不能的话输出NO。

贪心策略:1、我们可以把a序列分成m个连续的块,每个块的值的总和与b对应,对于每个块我们单独处理下,我们可以这个块的最大值开始向两边合并,切存在相邻的数小于它,然后一直合并下去就可以了!!! 
2、但这里有几个注意点,每个块不能合并的条件为这个块里所有元素都相等且块的长度不为1、b的总和和a的总和要相等,每一段,只要不完全相等,肯定可以都吃掉,因为就算有多个最大的,肯定有一个最大靠着一个小的,吃点之后,就比其余的都大了。

第一种写法模拟思路:这题无非就是找出n段来,然后就是对每一段进行操作了,所以写一个函数对每一段进行操作,把每一段数组传进这个函数里(注意如果要把数组作为参数传进函数里,必须要把这个数组写在main函数里面,然而我并不知道为什么,如果不写在main函数里面就错了),要输出的是哪个怪物往哪里吃,那就用一个结构体记录这个要吃别人的这个怪物的下标跟方向,那么要记录哪个怪物呢?肯定是每一段里面最大的怪物并且他左面或者右面有比他小的可以吃,这样这一段他肯定都可以吃掉,找到这个怪物就可以先沿着一个方向吃,然后在沿着另一个方向把剩下都吃掉。然后下一个难点就是这个怪物下标的变化了,可以发现的是,如果这个怪物先往右吃,那么他的下标是不变的,因为前面的数量根本没变,我们不用把每一个怪物的下标都变成正确的,只需要记录这个最大的就行,因为输出就是输出最大的行动轨迹,往左的话就是-1,-2,-3.这一部分看代码就明白了~

自己写看了CillyB思路之后自己写的:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;const int maxn = 5000;int b[maxn], cur, n, k;struct node{    int index, cmd;    node(){}    node(int ii, int cc) : index(ii), cmd(cc){}}ans[maxn];int solve(int *a, int len, int pre) //三个参数分别是这段数组,数组长度,跟前一个数组的下标{    if(len == 1) return 1;  //如果只有一个怪物说明不用吃    int flag = 0, max1 = -1;    for(int i = 1; i < len; i++)  //如果完全相同,说明肯定一个也吃不了        if(a[i] != a[i-1])        {            flag = 1;            break;        }    if(!flag) return 0;    for(int i = 0; i < len; i++)  //找出这个最大的值    {        max1 = max(max1, a[i]);    }    int s = -1;  //  cout << max1 << endl;     for(int i = 0; i < len; i++)  //找出最大怪物的下标,即是最大的,并且他旁边有比他小的    {        if(a[i] == max1)        {            if(i == 0 && a[i+1] != max1) {s = i;break;}            if(i == len-1 && a[i-1] != max1) {s = i; break;}            if(i && a[i-1] != a[i] || a[i+1] != a[i]) {s = i; break;}        }    }   // cout << s << endl;    if(s > 0 && a[s-1] == a[s])  //这句话是为了表示先往左吃还是先往右吃,这个左面一样,肯定只能往右吃,0也只能往右吃    {        for(int i = s + 1; i < len; i++)            ans[cur++] = node(pre+s+1, 1);  //往右吃前面的并么有变,所以下标不变,pre+s+1        for(int i = 0; i < s; i++)            ans[cur++] = node(pre+s+1-i, 0); //往左吃就先-1,-2,-3、、、、    }    else    {        for(int i = 0; i < s; i++)            ans[cur++] = node(pre+s+1-i, 0);        for(int i = s + 1; i < len; i++)            ans[cur++] = node(pre+1, 1); //如果先往左,这个怪物就到最前面了,所以他的下标是pre+1    }    return 1;}int main(){    int a[maxn];    while(~scanf("%d", &n))    {        for(int i = 0; i < n; i++)            scanf("%d", &a[i]);        scanf("%d", &k);        for(int i = 0; i < k; i++)            scanf("%d", &b[i]);        int num = 0, cnt = 0, cur1 = 0, i;        for(i = 0; i < n; i++)  //这里把一个数组的值赋给另一个数组的值,无非就是两种情况,一个是长的数组结束后,短的数组还没全        {                     //一个是短的数组全了 长的数组还没全            if(num + a[i] == b[cur1])            {                num = 0;                cur1++;            }            else if(num + a[i] < b[cur1])                num += a[i];            else                break;            if(cur1 == k) break;  //只要一个数组的长度达到了,就直接跳出        }        if(i < n - 1 || cur1 < k)         {             printf("NO\n");             continue;         }        cur1 = 0, num = 0, cnt = 0, cur = 0;        int flag = 0;        for(int i = 0; i < n; i++)        {            num += a[i];            cnt++;            if(num == b[cur1])            {                if(!solve(a+i-cnt+1, cnt, cur1))  //把数组的开头穿进去,用cnt限制这个数组的长度,达到了传进一段数的效果                {                    flag = 1;                    break;                }                num = 0;                cnt = 0;                cur1++;            }        }        if(flag) printf("NO\n");        else        {            printf("YES\n");            for(int i = 0; i < cur; i++)                printf("%d %c\n", ans[i].index, ans[i].cmd? 'R' : 'L');        }    }    return 0;}
照着同学的写的:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;const int maxn = 505;int b[maxn], n, k, cur;struct node{    int index, cmd;    node(int ii, int cc) : index(ii) , cmd(cc) {}    node(){}}ans[maxn];int solve(int *a, int len, int pre){    int flag = 0, max1 = -1, s = -1;    if(len == 1) return 1;    for(int i = 1; i < len; i++)        {            if(a[i] != a[i-1])            {                flag = 1;                break;            }        }    if(!flag) return 0;    for(int i = 0; i < len; i++)        max1 = max(max1, a[i]);    for(int i = 0; i < len; i++)    {        if(a[i] == max1)        {            if(i == 0 && a[i+1] != max1) {s = i; break;}            if(i == len-1 && a[i-1] != max1) {s = i; break;}            if(i && a[i] != a[i-1] || a[i] != a[i+1]) {s = i; break;}        }    }    if(s > 0 && a[s-1] == a[s])    {        for(int i = s+1; i < len; i++)            ans[cur++] = node(pre+s+1, 1);        for(int i = 0; i < s; i++)            ans[cur++] = node(pre+s+1-i, 0);    }    else    {        for(int i = 0; i < s; i++)            ans[cur++] = node(pre+s+1-i, 0);        for(int i = s+1; i < len; i++)            ans[cur++] = node(pre+1, 1);    }    return 1;}int main(){    int a[maxn];    while(~scanf("%d", &n))    {        cur = 0;        for(int i = 0; i < n; i++)            scanf("%d", &a[i]);        scanf("%d", &k);        for(int i = 0; i < k; i++)            scanf("%d", &b[i]);        int t = 0, i = 0, cnt1 =0, cnt2= 0;        for(i = 0; i < n; i++)        {            t += a[i];            cnt1++;            if(t == b[cnt2])            {                if(!solve(a+i-cnt1+1, cnt1, cnt2)) break;                t = 0;                cnt1 = 0;                cnt2++;            }            if(cnt2 == k) break;        }        if(i < n-1 || cnt2 != k) puts("NO\n");        else        {            puts("YES\n");            for(int i = 0; i < cur; i++)                 printf("%d %c\n", ans[i].index, ans[i].cmd ? 'R' : 'L');        }    }    return 0;}

%q:

这一种就是大多数大牛写的了,发现容器真的挺方便,一直不善于用容器,以后要多尝试.这种写法的精髓就是用vector把各组的下标都存进去,seg[1]就是存的第一组所有数字的下标,他们的值自然就是a[seg[i][j]]了;

#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<iostream>#include<algorithm>using namespace std;const int MAXN=100005;int a[MAXN],b[MAXN];vector<int>seg[MAXN];int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=n;i++)        scanf("%d",&a[i]);    int k;    scanf("%d",&k);    for(int i=1;i<=k;i++)        scanf("%d",&b[i]);    for(int i=1,j=1;i<=k;i++) //这种判断方式要学会,用短的数组每一段减去长数组的几个数,看最后会不会到0    {        while(j<=n && b[i]>0) //j <= n,保证了不超过这个数组长度        {            seg[i].push_back(j);// 用vector数组存进去下标,b数组只是为了记录能不能分段成功            b[i]-=a[j++];        }        if(i==k && j<=n)return 0*printf("NO"); //这里就是上面说的两种情况        if(b[i]!=0)return 0*printf("NO");    }    for(int i=1;i<=k;i++)  //这一步是为了看是不是所有的数字都是一样的    {        if((int)seg[i].size()==1)continue;        int mi=a[seg[i][0]],mx=a[seg[i][0]];        for(int j=0;j<(int)seg[i].size();j++)            mi=min(mi,a[seg[i][j]]),mx=max(mx,a[seg[i][j]]);        if(mi==mx)return 0*printf("NO");    }    printf("YES\n");    for(int i=1;i<=k;i++)  //一共k组,每一组进行操作    {        int mx=a[seg[i][0]];        for(int j=0;j<(int)seg[i].size();j++) //找到最大的数字            mx=max(mx,a[seg[i][j]]);        bool isok=0;        for(int j=0;j+1<(int)seg[i].size() && !isok;j++)            if(a[seg[i][j]]==mx && a[seg[i][j+1]]<mx) //看往左吃还是往右吃            {                for(int k=j;k+1<(int)seg[i].size();k++) 这里的j就是符合条件最大的怪物的下标(在这一段里的)                    printf("%d R\n",i+j);                for(int k=j;k>0;k--)  //用一个k表示-1,-2,-3                    printf("%d L\n",i+k);                isok=1;            }        for(int j=1;j<(int)seg[i].size() && !isok;j++)            if(a[seg[i][j]]==mx && a[seg[i][j-1]]<mx)            {                for(int k=j;k>0;k--)                    printf("%d L\n",i+k);                for(int k=j;k+1<(int)seg[i].size();k++)                    printf("%d R\n",i);                isok=1;            }    }    return 0;}



1 0
原创粉丝点击