palin-CSP-S2021T3

CSP-S 2021 T3 回文
传送门
不多BB直接上思路
20分思路
暴力枚举每一次操作,然后就没有然后了
40分思路
考虑在暴力枚举中优化
我们发现
一、当放入的数字在b的右半段时,只有当这个数字与与之对称的左半段数字相等时,才能放入
二、在b的同一半段中,每个数字只能出现一次
喜闻乐见的代码(40分)

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 1e6 + 100;
int T;
int n;
int a[maxn];
char ans[maxn];
int tot;
int lefta,righta,totb;
bool book = 0;
bool left[maxn], right[maxn];
int b[maxn];
bool check(){
    for(int i = 1;i <= n;i++){
        if(b[i] != b[2 * n + 1 - i])return false;
    }
    return true;
}
void dfs(int now){
    if(book)return;
    if(now > 2 * n){
        if(check()){
            for(int i = 1;i < tot;i++){
                putchar(ans[i]);
            }
            putchar('\n');
            book = 1;
            return;
        }
        return;
    }
    //L
    if((tot <= n && left[a[lefta]] == 0)){
        ans[tot] = 'L';
        b[totb] = a[lefta];
        left[a[lefta]] = 1;
        lefta++;totb++;
        tot++;
        dfs(now + 1);
        tot--;
        ans[tot] = 0;
        b[totb] = 0;
        lefta--;totb--;
        left[a[lefta]] = 0;
    }
    else if(tot > n && a[lefta] == b[2 * n + 1 - totb] && right[a[lefta]] == 0){
        ans[tot] = 'L';
        b[totb] = a[lefta];
        right[a[lefta]] = 1;
        lefta++;totb++;
        tot++;
        dfs(now + 1);
        tot--;
        ans[tot] = 0;
        b[totb] = 0;
        lefta--;totb--;
        right[a[lefta]] = 0;
    }
    //R
    if((tot <= n && left[a[righta]] == 0)){//
        ans[tot] = 'R';
        left[a[righta]] = 1;
        tot++;
        b[totb] = a[righta];
        righta--;totb++;
        dfs(now + 1);
        tot--;
        ans[tot] = 0;
        b[totb] = 0;
        righta++;totb--;
        left[a[righta]] = 0;
    }
    else if(tot > n && a[righta] == b[2 * n + 1 - totb] && right[a[righta]] == 0){
        ans[tot] = 'R';
        right[a[righta]] = 1;
        tot++;
        b[totb] = a[righta];
        righta--;totb++;
        dfs(now + 1);
        tot--;
        ans[tot] = 0;
        b[totb] = 0;
        righta++;totb--;
        right[a[righta]] = 0;
    }
}
void percent_40(){
    while(T--){
        memset(left,0,sizeof(left));
        memset(right,0,sizeof(right));
        book = 0;
        tot = 1;
        scanf("%d",&n);
        righta = n * 2;
        lefta = 1;
        totb = 1;
        for(int i = 1;i <= n * 2;i++){
            scanf("%d",&a[i]);
        }
        dfs(1);
        if(book == false){
            puts("-1");
        }
    }
}
int main(){/*
    freopen("palin.in","r",stdin);
    freopen("palin.out","w",stdout);*/
    scanf("%d",&T);
    percent_40();
    return 0;
}
/*
2
5
4 1 2 4 5 3 1 2 3 5
3
3 2 1 2 1 3

*/

100分
当我们将第一个数字拿出时,其实最后一个数字已经确定了,以此类推,我们就可以得出答案

#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int maxn = 1e6 + 100;
int T;
int n;
int a[maxn];
char ans[maxn];
int s[maxn];
int first[maxn],second[maxn];
int tp, pt;
bool check(int x,int l,int r,int y){//[x,y] as a ;[l,r] as b
    if(x == l && r == y)return 1;//finished
    if(x > l || r > y)return 0;//no solution
    if(a[x] == a[l - 1] && check(x + 1,l - 1,r,y)){
        ans[++tp] = 'L';
        return 1;
    }
    if(a[x] == a[r + 1] && check(x + 1,l,r + 1,y)){
        ans[++tp] = 'L';
        return 1;
    }
    if(a[y] == a[l - 1] && check(x,l - 1,r,y - 1)){
        ans[++tp] = 'R';
        return 1;
    }
    if(a[y] == a[r + 1] && check(x,l,r + 1,y - 1)){
        ans[++tp] = 'R';
        return 1;
    }
    return 0;
}
int main(){
    scanf("%d",&T);
    while(T--){
        pt = tp = 0;
        scanf("%d",&n);
        n *= 2;
        for(int i = 1;i <= n;i++){
            scanf("%d",&a[i]);
            if(first[a[i]] == 0)first[a[i]] = i;
            else second[a[i]] = i;
        }
        if(check(2,second[a[1]],second[a[1]],n)){//first as L
            ans[++tp] = 'L';
            int x = 1,y = n;
            while(tp){
                if(ans[tp] == 'L') s[++pt] = a[x++];
                else s[++pt] = a[y--];
                putchar(ans[tp--]);
            }
            while(pt){
                if(a[x] == s[pt]){
                    putchar('L');
                    x++;
                }
                else{
                    putchar('R');
                    y--;
                }
                --pt;
            }
        }
        else if(check(1,first[a[n]],first[a[n]],n - 1)){//first as R
            ans[++tp] = 'R';
            int x = 1,y = n;
            while(tp){
                if(ans[tp] == 'L') s[++pt] = a[x++];
                else s[++pt] = a[y--];
                putchar(ans[tp--]);
            }
            while(pt){
                if(a[x] == s[pt]){
                    putchar('L');
                    x++;
                }
                else{
                    putchar('R');
                    y--;
                }
                --pt;
            }
            
        }

        else printf("-1");//no solution
        putchar('\n');
        for(int i = 1;i <= n;i++){
            first[i] = second[i] = 0;
        }
    }
    return 0;
}
/*
2
5
4 1 2 4 5 3 1 2 3 5
3
3 2 1 2 1 3

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值