CSP-S 2021
让我们先忽略廊桥数量的限制来安排航班。我们维护一个空闲的廊桥队列,每到达一架航班,就给它安排编号最小的廊桥供其使用。
现在加上廊桥数量的限制。容易发现刚才的廊桥分配方法直接就帮我们解决了廊桥限制的问题:如果当前有
到这里做法就很清晰了:我们按照开头提到的分配方法来安排航班的停靠位置,记录各廊桥停靠的航班数,做一个前缀和,最后枚举分配给某个区的廊桥数,算出各情况下两区实际使用廊桥的航班数总和,即可解决本题。
第一篇题解写的挺好的,自己就不打了,嘿嘿。
#include<bits/stdc++.h> #define N 100005 #define X first #define Y second #define pii pair<int,int> using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } struct node{ int l,r; bool operator < (const node& A) const{return l==A.l?r<A.r:l<A.l;} }a[N],b[N]; int n,m1,m2,ans; int res1[N],res2[N]; void solve(node* t,int m,int* res){ priority_queue<pii,vector<pii>,greater<pii> > lq; priority_queue<int,vector<int>,greater<int> > wq; for(int i=1;i<=n;++i) wq.push(i); for(int i=1;i<=m;++i){ while(!lq.empty()&&t[i].l>=lq.top().X){ wq.push(lq.top().Y);lq.pop(); } if(wq.empty()) continue; int x=wq.top(); wq.pop(),res[x]++; lq.push(make_pair(t[i].r,x)); } for(int i=1;i<=n;++i) res[i]+=res[i-1]; } int main(){ n=read(),m1=read(),m2=read(); for(int i=1;i<=m1;++i) a[i].l=read(),a[i].r=read(); for(int i=1;i<=m2;++i) b[i].l=read(),b[i].r=read(); sort(a+1,a+1+m1),sort(b+1,b+1+m2); solve(a,m1,res1),solve(b,m2,res2); for(int i=0;i<=n;++i) ans=max(res1[i]+res2[n-i],ans); printf("%d\n",ans); return 0; }
首先肯定是区间dp,令
但是不同的形态可能会有不同的转移,如:(S)这种只能从S转移过来等等。所以只开两维的dp状态必然是不够的。
可以将两位的dp扩充为三维,第三位表示不同的形态种类,dp状态就变成了
-
: 形态如***...*
的括号序列(即全部是*
)。 -
: 形态如(...)
的括号序列(即左右直接被括号包裹且最左边括号与最右边的括号相互匹配)。 -
: 形态如(...)**(...)***
的括号序列(即左边以括号序列开头,右边以*
结尾)。 -
: 形态如(...)***(...)*(...)
的括号序列(即左边以括号序列开头,右边以括号序列结尾,注意:第2种形态也属于这种形态)。 -
: 形态如***(...)**(...)
的括号序列(即左边以*
开头,右边以括号序列结尾)。 -
: 形态如***(...)**(...)**
的括号序列(即左边以*
开头,右边以*结尾,注意:第1种形态也属于这种形态)。
设定完状态以后,转移就直接出来了,注意:为了防止连续超过 *
一起出现,转移的时候不能把两段*
拼接起来,在状态1的时候暴力判断一下两端的距离是否是
-
(直接特判)
没什么好解释的 -
,
表示第 位与第 位能否配对成括号,能则为 ,否则为 。
加括号时,里面可以是全*
,可以是有一边是*
, 也可以是两边都不是*
,唯独不能两边都是*
且中间有括号序列。 -
左边以括号序列开头且以括号序列结尾的是第3种,右边接一串*
,是第0种。 -
左边以括号序列开头,结尾随便,符合的有第2和第3种,右边接一个括号序列,是第1种。
记得加上直接一个括号序列的。 -
左边以*
开头,结尾随便,符合的有第4和第5种,右边接一个括号序列,是第1种。 -
左边以*
开头,以括号序列结尾,符合的是第4种,右边接一串*
,是第0种。
记得加上全是*
的。
最后,答案必须以括号序列开头,以括号序列结尾,所以直接是
这样,初始状态也就没什么问题了,对于所有的
最终时间复杂度
记得开long long,并且取模。
#include<bits/stdc++.h> #define N 505 #define mod 1000000007 #define int long long using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int n,k; char s[N]; int f[N][N][6]; // f 0 *** // f 1 () // f 2 ()*** // f 3 ()**() 包含 f 1 // f 4 ***()**() // f 5 ***()**()*** 包含 f 0 bool check(int a,int b){return (s[a]=='('||s[a]=='?')&&(s[b]==')'||s[b]=='?');} signed main(){ n=read(),k=read(); scanf("%s",s+1); for(int i=1;i<=n;++i) f[i][i-1][0]=1; for(int l=1;l<=n;++l){ for(int i=1;i+l-1<=n;++i){ int j=i+l-1; if(l<=k) f[i][j][0]=f[i][j-1][0]&&(s[j]=='?'||s[j]=='*'); if(l>=2){ if(check(i,j)) f[i][j][1]=(f[i+1][j-1][0]+f[i+1][j-1][2]+f[i+1][j-1][3]+f[i+1][j-1][4])%mod; for(int k=i;k<j;++k){ f[i][j][2]=(f[i][j][2]+f[i][k][3]*f[k+1][j][0])%mod; f[i][j][3]=(f[i][j][3]+(f[i][k][2]+f[i][k][3])*f[k+1][j][1])%mod; // f[i][j][4]=(f[i][j][4]+(f[i][k][4]+f[i][k][5])*f[k+1][j][1])%mod; //两种均可 f[i][j][4]=(f[i][j][4]+f[i][k][0]*f[k+1][j][3])%mod; f[i][j][5]=(f[i][j][5]+f[i][k][4]*f[k+1][j][0])%mod; } } f[i][j][5]=(f[i][j][5]+f[i][j][0])%mod; f[i][j][3]=(f[i][j][3]+f[i][j][1])%mod; } } printf("%lld\n",f[1][n][3]); return 0; }
枚举
考虑对其再来一个贪心,显然优先级为
#include<bits/stdc++.h> #define N 1000005 using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int T,n; char ans[N]; int a[N],b[N],L[N],R[N]; void init(){ memset(b,0,sizeof(b)); memset(ans,0,sizeof(ans)); memset(L,0,sizeof(L)); memset(R,0,sizeof(R)); } bool solve(int lst,int Li,int Ri){ if(Li==2) ans[1]='L'; else ans[1]='R'; int l=lst,r=lst,bg=2,ed=n-1; for(int i=1;i<n/2;++i){ if(R[a[Li]]==l-1) l--,Li++,ans[bg++]='L',ans[ed--]='L'; else if(R[a[Li]]==r+1) r++,Li++,ans[bg++]='L',ans[ed--]='R'; else if(L[a[Ri]]==l-1) l--,Ri--,ans[bg++]='R',ans[ed--]='L'; else if(L[a[Ri]]==r+1) r++,Ri--,ans[bg++]='R',ans[ed--]='R'; else return 0; } ans[n]='L'; for(int i=1;i<=n;++i) printf("%c",ans[i]);printf("\n"); return 1; } signed main(){ T=read(); while(T--){ init(); n=read()*2; for(int i=1;i<=n;++i) a[i]=read(),L[a[i]]?R[a[i]]=i:L[a[i]]=i; if(solve(R[a[1]],2,n)) continue; if(solve(L[a[n]],1,n-1)) continue; printf("-1\n"); } return 0; }
本文作者:南风未起
本文链接:https://www.cnblogs.com/jiangchen4122/p/17464587.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步