Codeforces Round #604 (Div. 2)

A. Beautiful String (CF 1265 A)

题目大意

当没有连续两个字母相同时,该字符串为美丽串,给定一个含a,b,c,?的字符串,要求将?替换成a,bc,使得该串为美丽串。若无法成为美丽串输出1

解题思路

很显然对于每个?的取值只跟它左右两个位置有关,而它一定能取到一个合法的值,只要跟左右不同即可,而如果一开始就有连续两个字母相同则输出1.

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
bool qwq;
char s[100500];
void check(int x){
s[x]='a';
if (x==0){
if (s[x+1]=='a') s[x]='b';
}
else{
if (s[x-1]=='a'||s[x+1]=='a') {
s[x]='b';
if (s[x-1]=='b'||s[x+1]=='b') {
s[x]='c';
if (s[x-1]=='c'||s[x+1]=='c') qwq=false;
}
}
}
}
void Input(void) {
scanf("%s",s);
int len=strlen(s);
qwq=true;
for(int i=0;i<len;++i){
if (qwq==false) break;
if (i!=0&&s[i]==s[i-1]) qwq=false;
if (s[i]=='?') check(i);
}
if (!qwq) printf("-1\n");
else printf("%s\n",s);
}
void Solve(void) {}
void Output(void) {}
main(void) {
int kase;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
read(kase);
for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
Input();
Solve();
Output();
}
}


B. Beautiful Numbers (CF 1265 B)

题目大意

给定一个排列,求每一个mn,是否存在l,r使得区间[l,r]1~m的一个全排列,存在则m为美丽数字。输出一个数字串,第i个数字表示i是否是美丽数字,是则1,否则0

解题思路

m=1的时候我们选择1的位置,然后我们从1的位置进行拓展,很显然我们每一次贪心的向左右两个数中较小的那个数进行扩展,才有可能得到一个1~m的全排列。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int n,l,r,pos,cnt,mi,ma;
const int N=2e5+8;
int p[N];
void Input(void) {
read(n);
for(int i=1;i<=n;++i) {
read(p[i]);
if (p[i]==1) pos=i;
}
}
void Solve(void) {
p[0]=p[n+1]=3e6;
l=r=pos;
cnt=1;
mi=ma=1;
putchar('1');
while(cnt<n){
if (l==1){
++r;
++cnt;
ma=MAX(ma,p[r]);
}else if (r==n){
--l;
++cnt;
ma=MAX(ma,p[l]);
}else if (p[l-1]>p[r+1]) {
++r;
++cnt;
ma=MAX(ma,p[r]);
}
else{
--l;
++cnt;
ma=MAX(ma,p[l]);
}
if (cnt==ma-mi+1) putchar('1');
else putchar('0');
}
puts("");
}
void Output(void) {}
main(void) {
int kase;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
read(kase);
for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
Input();
Solve();
Output();
}
}


C. Beautiful Regional Contest (CF 1265 C)

题目大意

n个选手参加比赛,递减给出它们解决的题数,分配g个金牌s个银牌和b个铜牌,要求g<sg<b,且g+s+bn2,且获得金牌的选手的题数严格大于获得银牌选手的题数,获得银牌的选手题数严格大于获得铜牌选手的题数,获得铜牌的选手题数严格大于获得铁牌(无牌)(来杯拿铁咖啡)选手的题数,问能否做到,若能,给定一个可行的分配方案,使得发牌数最大。

解题思路

题目对于g有大小限制而sb之间没有,则我们让g尽可能小就好了,即选解题数最高的那一组选手全部发金牌,然后发银牌,直到g>s,剩下的选手全部发铜牌,直到发的牌数恰好小于n2即可,做不到则不可行。
如果你是良心比赛方可以最后把sb调换一下。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int n,g,s,b,qwq,re;
const int N=4e5+8;
int num[N],cnt[N];
void Input(void) {
qwq=0;
num[0]=-1;
read(n);
for(int a,i=1;i<=n;++i) {
read(a);
if (num[qwq]!=a) num[++qwq]=a;
++cnt[qwq];
}
s=g=b=re=0;
}
void Solve(void) {
g=cnt[1];
int i=2;
while(s<=g) s+=cnt[i++];
while(b<=g) b+=cnt[i++];
if (s+g+b>n/2) g=s=b=0;
else {while(s+g+b<=n/2) b+=cnt[i++]; b-=cnt[--i];}
printf("%d %d %d\n",g,s,b);
for(int i=1;i<=n;++i) num[i]=cnt[i]=0;
}
void Output(void) {}
main(void) {
int kase;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
read(kase);
for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
Input();
Solve();
Output();
}
}


D. Beautiful Sequence (CF 1265 D)

题目大意

给了a0b1c2d3,要求排成一个序列,使得俩俩差值为1,输出任意符合要求序列即可,没有则NO

解题思路

  • 如果有三个数是0个,则第四个数数量为1则可行,否则不可行。
  • 如果有两个数是0个,则看另外两个数的差值是否为1,是则由植树原理再判断二者的差值是否为一,是则可行,其余情况均不可行。
  • 如果有一个数是0个,则看这个数是多少,若为12则不可行,当为03时,不失一般性,假设是0的数为0个,那么我们排列1,2,3,由植树原理可知如果cnt=c(b1+d1+1)2则可行,即1,2,1,2,1,2......,2,1,2,3,2,3,2......2,3,如此排列,若cnt1则在序列最左边放一个2,若为2则在最左边和最右边各放一个2即可。
  • 如果有零个数是0个,我们考虑0,12,3,首先bacd,否则不可行。我们按照,0,1,0,1............2,3,2,3如此排好后,考虑12之间的排列,我们如此2,1,2,1.....排列,直到用光1或者2,此时如果还有剩余的,假设1还有剩余,若剩余1个,则放到最左边,否则不可行,若2还有剩余,若剩余1个,则放到最右边,否则不可行.

综上即可。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int a,b,c,d,mi,cnt;
bool qwq;
void Input(void) {
cnt=0;
read(a);
read(b);
read(c);
read(d);
cnt=(a==0)+(b==0)+(c==0)+(d==0);
}
void check1(){
int sign=0;
if (a==0) sign=0;
else if (b==0) sign=1;
else if (c==0) sign=2;
else sign=3;
if (sign==1||sign==2){
qwq=true;
return;
}
if (sign==3){
b-=a-1;
b-=c-1;
--b;
if (b<0||b>2){
qwq=true;
return;
}
else{
printf("YES\n");
if (b) --b,printf("1 ");
for(int i=1;i<=a;++i) printf("0 1 ");
for(int i=1;i<c;++i) printf("2 1 ");
printf("2");
if (b) printf(" 1\n");
else printf("\n");
return;
}
}
else{
c-=b-1;
c-=d-1;
--c;
if (c<0||c>2){
qwq=true;
return;
}
else{
printf("YES\n");
if (c) --c,printf("2 ");
for(int i=1;i<=b;++i) printf("1 2 ");
for(int i=1;i<d;++i) printf("3 2 ");
printf("3");
if (c) printf(" 2\n");
else printf("\n");
return;
}
}
}
void check2(){
int s1=-1,s2=-1;
int cnt[4];
cnt[0]=a;
cnt[1]=b;
cnt[2]=c;
cnt[3]=d;
if (a!=0) s1=0;
if (b!=0) if (s1==-1) s1=1;else s2=1;
if (c!=0) if (s1==-1) s1=2;else s2=2;
if (d!=0) if (s1==-1) s1=3;else s2=3;
if (s2-s1>1) {
qwq=true;
return;
}
else{
if (ABS(cnt[s2]-cnt[s1])>1){
qwq=true;
return;
}
else{
printf("YES\n");
if (cnt[s2]>cnt[s1]) {for(int i=1;i<=cnt[s1];++i) printf("%d %d ",s2,s1); printf("%d\n",s2);}
else if (cnt[s2]<cnt[s1]) {for(int i=1;i<=cnt[s2];++i) printf("%d %d ",s1,s2); printf("%d\n",s1);}
else for(int i=1;i<=cnt[s1];++i) printf("%d %d%c",s1,s2,i==cnt[s1]?'\n':' ');
return;
}
}
}
void check3(){
int si=0;
int cnt[4];
cnt[0]=a;
cnt[1]=b;
cnt[2]=c;
cnt[3]=d;
for(int i=0;i<4;++i) if (cnt[i]!=0) si=i;
if (cnt[si]==1){
printf("YES\n");
printf("%d\n",si);
return;
}
else {
qwq=true;
return;
}
}
void Solve(void) {
qwq=false;
if (a>b&&(c!=0||d!=0)) qwq=true;
else if (d>c&&(b!=0||a!=0)) qwq=true;
if (!qwq){
if (cnt==0){
b-=a;
c-=d;
mi=MIN(b,c);
b-=mi;
c-=mi;
if (b==1||c==1){
printf("YES\n");
if (b==1) {
printf("1 ");
for(int i=1;i<=a;++i) printf("0 1 ");
for(int i=1;i<=mi;++i) printf("2 1 ");
for(int i=1;i<=d;++i) printf("2 3%c",i==d?'\n':' ');
}
else{
for(int i=1;i<=a;++i) printf("0 1 ");
for(int i=1;i<=mi;++i) printf("2 1 ");
for(int i=1;i<=d;++i) printf("2 3 ");
printf("2\n");
}
}
else if (b==c){
printf("YES\n");
for(int i=1;i<=a;++i) printf("0 1 ");
for(int i=1;i<=mi;++i) printf("2 1 ");
for(int i=1;i<=d;++i) printf("2 3%c",i==d?'\n':' ');
}
else qwq=true;
}
else{
if (cnt==1) check1();
else if (cnt==2) check2();
else if (cnt==3) check3();
}
}
if (qwq) printf("NO\n");
}
void Output(void) {}
main(void) {
//int kase;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
//read(kase);
//for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
Input();
Solve();
Output();
//}
}

由于昨晚放弃思考了所以代码写了巨长……

E. Beautiful Mirrors (CF 1265 E)

题目大意

n枚镜子,每天问一枚镜子,从第一枚镜子开始问Creatnx是否漂亮,是则下一天跳转到下一个镜子,否则下一天从第一枚镜子重新开始问。当最后一枚镜子即第n枚镜子说她漂亮时,她就变得很开心。问她变得开心的期望天数。

解题思路

期望题,我们通常逆推,即从结果推到初始状态。
f(i)表示从第i枚镜子开始问,变得开心(即问到第n枚镜子得到漂亮回答)的期望天数。
根据期望的定义,我们有f(n+1)=0以及f(i)=pi100f(i+1)+(1pi100)f(1)
即对于第i天,它有pi100的概率需要f(i+1)才变得开心,也有(1pi100)的概率需要f(1)才变得开心。
右式一共有n个方程,我们可以用高斯消元即可解出答案f(1),但复杂度是O(n3),会超时。
由于逆推状态不当,导致式子中存在f(1),这对答案求值造成很大不便,我们需要修改状态。
由于回答不漂亮会回到第一枚镜子,那么我们希望第一枚镜子的状态会是一个已知状态。
我们设f(i)表示从第一枚镜子问,问到第i枚镜子且回答漂亮的期望天数。
f(0)=0f(i)=f(i1)+pi100+(1pi100)(f(i)+1)
即我们要问第i枚镜子,首先需要期望天数f(i1)问到第i1枚镜子并得到漂亮的回答,然后对于第i枚镜子,我们有pi100的概率花一天得到漂亮的回答,也有(1pi100)的概率得到不漂亮回答,这时需要再花f(i)天才能得到漂亮的回答,所以总共需要f(i)+11是问第i枚镜子得到不漂亮的回答的那一天),化简一下即可得到f(i)=(f(i1)+1)×100pi,递推O(n)即可得到答案f(n)
(f(i)=pi100(f(i1)+1)+(1pi100)(f(i1)+1+f(i))这个和上面是等价的,即有pi100的概率得到漂亮答案,这时需要的天数是f(i1)+1,也有(1pi100)的概率得到了不漂亮回答,这时我们需要从第一枚镜子重新问,此时得到第i枚镜子的漂亮回答的天数是(f(i1)+1+f(i)))

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
const long long mo=998244353;
long long kuai(long long a,long long b){
int qwq=1;
while(b){
if (b&1) qwq=a*qwq%mo;
a=a*a%mo;
b>>=1;
}
return qwq;
}
void Input(void) {
int n;
long long ans=0,f;
read(n);
for(int i=1;i<=n;++i){
read(f);
ans=(ans+1)%mo*100%mo*kuai(f,mo-2)%mo;
}
printf("%lld\n",ans);
}
void Solve(void) {}
void Output(void) {}
main(void) {
//int kase;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
//read(kase);
//for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
Input();
Solve();
Output();
//}
}


C. Beautiful Mirrors with queries (CF 1264 C)

题目大意

n枚镜子,每天问一枚镜子,从第一枚镜子开始问Creatnx是否漂亮,是则下一天跳转到下一个镜子,否则下一天从小于当前镜子编号的标有checkpoint的最大编号的镜子问。当最后一枚镜子即第n枚镜子说她漂亮时,她就变得很开心。
q次操作,每次操作将第i枚镜子设为checkpoint(如果之前不是checkpoint)或者取消checkpoint(如果之前是checkpoint),对于每次操作,回答她变得开心的期望天数。

解题思路

由于镜子回答不漂亮的时候Creatnx不再是从第一枚镜子问,checkpoint相当于把连续的镜子分成了若干段,不同段之间互不干扰,对于每一段[l,r],我们都可以假想是从第一枚镜子问到第rl+1枚镜子并得到漂亮回答的期望天数,由期望的线性可加性,我们把不同段的期望天数相加即可得到答案。而每次操作仅仅增加或移除一个checkpoint,如果我们能够快速知道某段区间对答案贡献的期望天数,即可快速解决此题。

上一题中一开始的递推式f(i)=pi100f(i+1)+(1pi100)f(1),某人通过解前几项的规律得出f(1)=1+p1+p1p2++p1p2pn1p1p2pn,这是我们从1号镜子开始问问到第n号镜子并得到漂亮回答的答案。其实这个从后来的递推式f(i)=(f(i1)+1)pi展开也可得到。

这样子的话,对于一个新添加的checkpoint,记为mid,再设编号小于checkpoint编号的最大checkpoint编号为l,编号大于checkpoint编号的最小checkpoint编号为r,则从1l1的期望天数,从rn的期望天数并没有受到影响,而从lr1的期望天数被分成了两部分,一部分是从lmid1,一部分是midr1,我们只要减去lr1的期望贡献,再加上lmid1midr1的期望贡献即可得到新的答案,移除的话即减去lmid1midr1的期望贡献,加回lr1的期望贡献即可。

从上面展开递推式的过程(这里没有)我们可以知道,对于从uv都得到漂亮回答的期望天数为1+pu+pupu+1++pupu+1pv1pupu+1pv=AB,由此我们只要预处理si=p1p2pi以及ti=p1+p1p2++p1p2pi,那么对于从uv都得到漂亮回答的情况,A=tv1tu2p1p2pu1=tv1tu2su1B=svsu1,二者相除即是期望天数.

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
int n,q;
const int N=2e5+8;
const long long mo=998244353;
long long psum[N],pmul[N],ipmul[N],p[N];
long long ans;
set<long long> mirror;
long long kuai(long long a,long long b){
long long qwq=1;
while(b){
if (b&1) qwq=qwq*a%mo;
a=a*a%mo;
b>>=1;
}
return qwq;
}
void Input(void) {
read(n);
read(q);
long long tmp=kuai(100,mo-2);
for(int i=1;i<=n;++i){
read(p[i]);
p[i]=p[i]*tmp%mo;
}
}
long long getans(long long l,long long r){
long long qwq=0;
if (l==1) qwq=0;
else qwq=psum[l-2];
return (pmul[l-1]*(psum[r-1]-qwq)%mo*ipmul[r]%mo*ipmul[l-1])%mo;
}
void Solve(void) {
pmul[0]=1;
ipmul[0]=1;
psum[0]=1;
for(int i=1;i<=n;++i){
pmul[i]=pmul[i-1]*p[i]%mo;
psum[i]=(psum[i-1]+pmul[i])%mo;
ipmul[i]=kuai(pmul[i],mo-2);
}
ans=getans(1,n);
mirror.insert(1);
mirror.insert(n+1);
for(int u,i=1;i<=q;++i){
read(u);
if (mirror.count(u)){
auto mid=mirror.find(u);
auto l=mid,r=mid;
--l;
++r;
ans-=getans(*l,*mid-1);
ans-=getans(*mid,*r-1);
ans+=getans(*l,*r-1);
mirror.erase(u);
}
else{
auto mid=mirror.insert(u).first;
auto l=mid,r=mid;
--l;
++r;
ans+=getans(*l,*mid-1);
ans+=getans(*mid,*r-1);
ans-=getans(*l,*r-1);
}
ans%=mo;
while(ans<0) ans+=mo;
printf("%lld\n",ans);
}
}
void Output(void) {}
main(void) {
//int kase;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
//read(kase);
//for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
Input();
Solve();
Output();
//}
}


F. Beautiful Bracket Sequence (easy version)

题目大意

定义一个合法的括号串以及它的深度:

  • 合法的括号串即左括号数量等于右括号数量且对于任意一个左括号(都能找到一个与之匹配的右括号)
  • 空括号串的深度为0
  • 当一个合法括号串t的深度为d,则(t)括号串的深度为d+1
  • 如果有两个合法的括号串st,则括号串st的深度为两者中的较大值

则对于一个(可能不合法)的括号串,它的深度为它所有合法括号子串(可以不连续)深度的最大值。
现给定一个含有"(" "?" 和")"括号串,对"?"取所有值("("或")"),求所有情况该括号串深度和。

解题思路

我们先解决如何计算一个括号串的深度。
这是个区间问题,我们定义dp[i][j]表示s[i...j]的深度
如果s[i]=(s[j]=)或者其中有一个或两个是?,那么dp[i][j]=dp[i+1][j1]+1
否则dp[i][j]=max(dp[i+1][j],dp[i][j1])
这就解决了深度的问题。
从中我们考虑每对括号对答案的贡献,即设dp[i][j]表示s[i...j]中的括号取遍所有情况,该串的深度和。
s[i](时,此时s[i]s[j]对答案没有任何贡献,那么dp[i][j]+=dp[i+1][j]
s[j])时,此时s[i]s[j]对答案没有任何贡献,那么dp[i][j]+=dp[i][j1]
注意到如果s[i](s[j]),我们加上了两次dp[i+1][j1]的贡献,此时要dp[i][j]=dp[i+1][j1]
而如果s[i]=(s[j]=)或者其中有一个或两个是?,即s[i])s[j](,这个时候s[i]s[j]可以形成一对括号,对答案贡献了1,若区间[i+1,j1]k个问号,则有2k种情况,此时对答案贡献为2k,故dp[i][j]+=dp[i+1][j1]+2k
综上,即:

  • s[i]( , dp[i][j]+=dp[i+1][j]
  • s[j]) , dp[i][j]+=dp[i][j1]
  • s[i]( && s[j]) , dp[i][j]=dp[i+1][j1]
  • s[i]) && s[j]( , dp[i][j]+=dp[i+1][j1]+2k

区间DP。

神奇的代码
#include <bits/stdc++.h>
#define MIN(a,b) ((((a)<(b)?(a):(b))))
#define MAX(a,b) ((((a)>(b)?(a):(b))))
#define ABS(a) ((((a)>0?(a):-(a))))
using namespace std;
template <typename T>
void read(T &x) {
int s = 0, c = getchar();
x = 0;
while (isspace(c)) c = getchar();
if (c == 45) s = 1, c = getchar();
while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
if (s) x = -x;
}
template <typename T>
void write(T x, char c = ' ') {
int b[40], l = 0;
if (x < 0) putchar(45), x = -x;
while (x > 0) b[l++] = x % 10, x /= 10;
if (!l) putchar(48);
while (l) putchar(b[--l] | 48);
putchar(c);
}
const long long mo=998244353;
const int N=2e3+8;
char s[N];
long long sum[N],dp[N][N];
int len;
void Input(void) {
scanf("%s",s);
}
long long kuai(long long a,long long b){
long long qwq=1;
while(b){
if (b&1) qwq=qwq*a%mo;
a=a*a%mo;
b>>=1;
}
return qwq;
}
void Solve(void) {
len=strlen(s);
sum[0]=(s[0]=='?');
for(int i=1;i<len;++i) sum[i]=sum[i-1]+(s[i]=='?');
for(int l=2;l<=len;++l)
for(int j,i=0;i<len-l+1;++i){
j=i+l-1;
if (s[i]!='(') dp[i][j]=(dp[i][j]+dp[i+1][j])%mo;
if (s[j]!=')') dp[i][j]=(dp[i][j]+dp[i][j-1])%mo;
if (s[i]!='('&&s[j]!=')') dp[i][j]=(dp[i][j]-dp[i+1][j-1]+mo)%mo;
if (s[i]!=')'&&s[j]!='(') dp[i][j]=((dp[i][j]+dp[i+1][j-1])%mo+kuai(2ll,sum[j-1]-sum[i]))%mo;
}
}
void Output(void) {
printf("%lld\n",dp[0][len-1]);
}
main(void) {
//int kase;
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
//read(kase);
//for (int i = 1; i <= kase; i++) {
//printf("Case #%d: ", i);
Input();
Solve();
Output();
//}
}


这次的题都是贪心构造和期望和DPqwq。

本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/11995096.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(523)  评论(4编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.