题意

https://loj.ac/problem/2713

思路

对于 \(\text{P1}\) 的档,首先可以看出 \(O(n^3)\) 的方法,即用 \(O(n^3)\) 的 \(\text{DP}\) 判断合法性以及记录路径。具体是这样的,因为括号匹配可以用一个弹栈的模型去表示(前括号入,后括号弹),用一个整数就可以表示当前的匹配状态,所以用 \(dp_{i,j,k}\) 表示第 \(i\) 个括号,忽视蓝色括号栈中有 \(j\) 个前括号,忽视红色括号栈中有 \(k\) 个前括号。则如果加入一个红前括号,则 \(j\) 加一;若加入一个蓝前括号,则 \(k\) 加一;若加入一个绿前括号,则 \(j,k\) 均加一。后括号同理。

从这个转移来看,似乎就是一个走棋盘的模型,但是单看走棋盘似乎也看不出什么。那么把棋盘拍扁成一维,只保存当前位置到起点的距离。设 \((0,0)​\) 在最左上角,那么向右或下走距离加 \(1​\) ,右下则加 \(2​\) ,反之同理。不难发现,如果存在把距离变回零的方案,则棋盘上可以走回 \((0,0)​\) 的方案肯定可以构造出来。

一顿操作,问题变成了给定一个加减号序列,你需要在里面适当位置填上 \(1\) 或 \(2\) ,满足任意前缀大于等于 \(0\) ,最终总和等于 \(0\) 。

这时候,贪心策略也渐渐显然,通过维护某一时刻最大的前缀 \(u\) ,最小的前缀 \(d\) 。扫到某一时刻,碰到加号(左括号)则 \(u+2,d+1\),碰到减号(右括号)则 \(u-1,d-2\) ,最大前缀小于零则要求一无法满足,而最小前缀小于零就补到零(表示可以将其中一个的 \(-2\) 变成了 \(-1\) ),最后得到的 \(d\) 不是零就说明加号过多,要求二无法满足,同样不合法。

我们得到的 \(u\) 就告诉我们如果只有 \(+2,-1\) 时,最后会是几,那我们就倒着扫这么多个数,把 \(+2\) 变成 \(+1\) ,\(-1\) 变成 \(-2\) 。

这样就得到了这个加减号序列,最后我们只用把 \(+1\) 换成红蓝交替的前括号,\(-1\) 换成红蓝交替的后括号,\(+2,-2\) 分别换成绿色前后括号即可。

会 \(O(n)\) 判断合法性,就直接按照这个 \(\text{DP}\) 就可以切 \(\text{P2}\) 档了,可以直接看代码。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
template<typename T,typename _T>inline bool chk_min(T &x,const _T y){return y<x?x=y,1:0;}
template<typename T,typename _T>inline bool chk_max(T &x,const _T y){return x<y?x=y,1:0;}
typedef long long ll;
namespace Subtask1
{
const int N=1e6+5;
char str[N];
int ans[N];
int n;
int check()
{
int d=0,u=0;
FOR(i,1,n)
{
if(str[i]=='(')d+=1,u+=2;
else
{
d-=2,u-=1;
chk_max(d,0);
if(u<0)return -1;
}
}
if(d>0)return -1;
return u;
}
void Solve()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",str+1);
n=strlen(str+1);
int res=check();
if(res==-1){printf("impossible\n");continue;}
FOR(i,1,n)ans[i]=0;
int flg=-1;
if(res)DOR(i,n,1)
{
if(str[i]=='(')ans[i]=flg,flg=-flg;
else ans[i]=2;
res--;
if(!res)break;
}
flg=-1;
FOR(i,1,n)if(str[i]==')')
{
if(ans[i]==2)break;
ans[i]=flg,flg=-flg;
}
FOR(i,1,n)
{
if(ans[i]==1)putchar('R');
else if(ans[i]==-1)putchar('B');
else putchar('G');
}
puts("");
}
}
};
namespace Subtask2
{
const int P=1e9+7;
const int N=305;
int dp[N][N][N<<1];
int ans[N];
void pls(int &x,int y){x+=y;if(x>=P)x-=P;}
void Solve()
{
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
FOR(i,0,299)
{
FOR(j,0,i)FOR(k,0,2*i)
{
pls(dp[i+1][j+1][k+2],dp[i][j][k]);
if(k)pls(dp[i+1][std::max(0,j-2)][k-1],dp[i][j][k]);
}
FOR(j,0,2*i)pls(ans[i+1],dp[i+1][0][j]);
}
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
printf("%d\n",ans[n]);
}
}
}; int main()
{
int knd;
scanf("%d",&knd);
if(knd==1)Subtask1::Solve();
else if(knd==2)Subtask2::Solve();
return 0;
}

BalkanOI 2018 Parentrises(贪心+基础DP)的更多相关文章

  1. 「BalkanOI 2018 Day2」Parentrises

    「BalkanOI 2018 Day2」Parentrises part1 显然可以直接贪心. 右括号记-1,左括号记1. 默认起始全部绿色,不染色. 策略如下: 从左往右扫,如果右括号个数大于左括号 ...

  2. 基础dp

    队友的建议,让我去学一学kuangbin的基础dp,在这里小小的整理总结一下吧. 首先我感觉自己还远远不够称为一个dp选手,一是这些题目还远不够,二是定义状态的经验不足.不过这些题目让我在一定程度上加 ...

  3. 贪心/构造/DP 杂题选做Ⅱ

    由于换了台电脑,而我的贪心 & 构造能力依然很拉跨,所以决定再开一个坑( 前传: 贪心/构造/DP 杂题选做 u1s1 我预感还有Ⅲ(欸,这不是我在多项式Ⅱ中说过的原话吗) 24. P5912 ...

  4. poj2709 贪心基础

    D - 贪心 基础 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:65536KB     64bi ...

  5. uva11292贪心基础题目

    C - 贪心 基础 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:65536KB     64bi ...

  6. hdu 1009 贪心基础题

    B - 贪心 基础 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64bi ...

  7. L贪心基础

    <span style="color:#330099;">/* L - 贪心 基础 Time Limit:1000MS Memory Limit:65536KB 64b ...

  8. ALGO-13_蓝桥杯_算法训练_拦截导弹(贪心,DP)

    问题描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...

  9. 基础DP(初级版)

    本文主要内容为基础DP,内容来源为<算法导论>,总结不易,转载请注明出处. 后续会更新出kuanbin关于基础DP的题目...... 动态规划: 动态规划用于子问题重叠的情况,即不同的子问 ...

随机推荐

  1. 转载--python模块

    模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个函数才 ...

  2. char和QChar(Unicode的编码与内存里的值还不是一回事)

    char类型是c/c++中内置的类型,描述了1个字节的内存信息的解析.比如: char gemfield=’g’;那么在由gemfield标记的这块内存的大小就是1个字节,信息就是01100111,8 ...

  3. SSMP一次请求数据处理过程分析

    控制器代码 @RequestMapping("/changeUserPwd") public TranMessage changeUserPwd(String oriPwd, St ...

  4. cnblog项目--20190309

    第一个真正意义的Django项目 ! 预计时间5天  20190309--20190314 目标:学会Django的使用,理解模块关系!   querset  相当于一个存放列表的字典     day ...

  5. zookeeper的使用demo(c#/java)

    Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储,但是 Zookeeper 并不是用来专门存储数据的,它 ...

  6. C语言中格式字符串

    C语言中格式字符串的一般形式为: %[标志][输出最小宽度][.精度][长度]类型, 其中方括号[]中的项为可选项. 一.类型 我们用一定的字符用以表示输出数据的类型,其格式符和意义下表所示: 字符  ...

  7. Emmet:HTML/CSS代码快速编写神器教程

    Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生.它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示: ...

  8. 18.12.02-C语言练习:韩信点兵

    C语言练习:韩信点兵 题目说明:本题是中国经典问题,有多种解法,从数论课程角度看,是一个不定方程组,而且答案不唯一. 但这里采用程序解法,使用的是暴力破解.枚举可能的解,然后根据条件判断,满足所有条件 ...

  9. 用mongols轻松打造websocket应用

    用websocket做聊天系统是非常合适的. mongols是一个运行于linux系统之上的开源c++库,可轻松开启一个websocket服务器. 首先,build一个websocket服务器. #i ...

  10. hi-nginx-1.4.9正式发布,支持javascript后端开发

    hi-nginx-1.4.9已经发布. 更新: 支持javascript后端开发 修复脚本搜索的一个bug 从这一版开始,hi-nginx开始支持javascript,这意味着把javascript应 ...