我的内心:
T1:骗30分
T2:骗15分
T3:骗15分
T4:暴力拿一点点分数
然后我想冲二等奖
我的内心:
T1:0
T2:0
T3:0
T4:0
好家伙。。。
祝大家明天AK!
1.廊桥分配
2.括号序列
(不要问我3,4去哪里了,我还在写)
//此题解来自于Youthjoy_Creator
这题贪心+堆
国际,国内航班分别计算。
假设我们有足够多的廊桥,我们可以让尽量多的飞机停在尽量靠前的地方,这样一个前缀和就可得到当某一区分配了 pp 个廊桥的地方了。
如何计算这玩意。
ai,bi≤100000000
压一下,变成 2*10^5 的数据范围
用一个 priority_queue
维护当前可用的廊桥编号,用一个数组维护当前飞机如果停靠在廊桥上的话是几号。
以下假设这个优先队列是小根堆。
考虑每一个时间点,如果飞机飞入,取出队首,让这架飞机停靠。
如果飞机飞出,找到这架飞机停靠的廊桥然后压入。
做两遍这个操作就可以了。
时间复杂度:n log n(舒服)
//说句实话T1比T3难
好了,上代码
#include
#define N 100009
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
inline ll read(){
ll x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}
return x*f;
}
ll n,m[2],rk[2][2*N],in[2][2*N],out[2][2*N],nw[2][2*N],ans[2][N],ANS;
struct node2{
ll id,k;
bool operator<(const node2&x)const{return k qu[2];
void solve(ll x){
for(int i=1;i<=m[x];i++) qu[x].push(-i);
for(int i=1;i<=2*m[x];i++){
if(in[x][i]){
ll u=-qu[x].top();qu[x].pop();
nw[x][in[x][i]]=u;
ans[x][u]++;
}
else qu[x].push(-nw[x][out[x][i]]),nw[x][out[x][i]]=0;
}
for(int i=1;i<=100000;i++) ans[x][i]+=ans[x][i-1];
}
int main(){
//freopen("airport.in","r",stdin);
//freopen("airport.out","w",stdout);
n=read(),m[0]=read(),m[1]=read();
for(int i=1;i<=m[0];i++) q[2*i-1].k=read(),q[2*i-1].id=2*i-1,q[2*i].k=read(),q[2*i].id=2*i;
sort(q+1,q+2*m[0]+1);
for(int i=1;i<=2*m[0];i++) rk[0][q[i].id]=i;
for(int i=1;i<=m[0];i++) a[0][i].l=rk[0][2*i-1],a[0][i].r=rk[0][2*i],in[0][a[0][i].l]=i,out[0][a[0][i].r]=i;
for(int i=1;i<=m[1];i++) q[2*i-1].k=read(),q[2*i-1].id=2*i-1,q[2*i].k=read(),q[2*i].id=2*i;
sort(q+1,q+2*m[1]+1);
for(int i=1;i<=2*m[1];i++) rk[1][q[i].id]=i;
for(int i=1;i<=m[1];i++) a[1][i].l=rk[1][2*i-1],a[1][i].r=rk[1][2*i],in[1][a[1][i].l]=i,out[1][a[1][i].r]=i;
solve(0),solve(1);
for(int i=0;i<=n;i++) ANS=max(ANS,ans[0][i]+ans[1][n-i]);
printf("%lld\n",ANS);
return 0;
}
//此题解来自于QAQQWQ
看到题面,容易想到是区间 dp。设 dp_{i,j}dpi,j 为将 i 到 j 的位置中所有问号填满,使其成为符合规范的超级括号序列的方案种数,考虑 dp_{i,j}dpi,j 可以由那些情况转移而来。
开始 O(n))预处理一次可能成为 * 的长度可以做到 O(1) 判断一段串是否可能全为 * 。
但是写完代码后发现第二个样例无法通过,会算重。考虑这样一种情况 ()()()
它会在两个分割点被计算两次。那么我们可以限制它在一个方向上合并,这样做后答案是正确的,复杂度 O(n^4) 可以得到 40 分
加上前缀和可以优化到 O(n^3) 可以通过本题。
//其实就是前缀和压维。。。
#include
using namespace std;
int n,k;
const int mod=1e9+7;
long long dp[509][509],dps[509][509],sum[509][509];
int xh[509];
char s[509];
int read(){
int sm=0,d=1;
char c=getchar();
while(c>'9'||c<'0'){
if(c=='-'){
d=-1;
}
c=getchar();
}
while(c>='0'&&c<='9'){
sm*=10;
sm+=c-'0';
c=getchar();
}
return sm*d;
}
bool check(int l,int r){
return (xh[r]>=r-l+1&&r-l+1<=k);
}
int main(){
n=read();
k=read();
cin>>s+1;
for(int i=1;i<=n;i++){
if(s[i]=='?'||s[i]=='*'){
xh[i]=xh[i-1]+1;
}
else xh[i]=0;
}
for(int j=1;j<=n;j++){
for(int i=j-1;i;i--){
if((s[i]=='('||s[i]=='?')&&(s[j]==')'||s[j]=='?')){
if(check(i+1,j-1)){
dp[i][j]=(dp[i][j]+1)%mod;
}
dp[i][j]=(dp[i][j]+dps[i+1][j-1])%mod;
for(int mid=i+1;mid
考试的时候我一道题差点忘打freopen。。。