\(T1\)括号序列

——那是,朝思夜想也未尝得到的自由

一个比较常见的转化,考虑如何判断前一段和后一段能够拼成一个合法的括号序列

充要条件:

前半部分,‘(’看为\(1\), ‘)’看为\(-1\),前缀和一直\(\geq 0\)

后半部分,‘)’看为\(1\), '('看做\(-1\),后缀和一直\(\geq 0\)

并且前缀和等于后缀和

然后,依照这个结论可以使用暴力拿到\(70pts\),\(100pts\)需要写的很麻烦,所以换一种写法

\(70pts\):

暴力统计每个位置满足条件的就好了

#include<cstdio>
using namespace std;
int n,q,l,r,cn[8010];
char s[8010];
int main()
{
scanf("%d%d%s",&n,&q,s+1);
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l,&r);
long long res=0;
int li=l-1,lt=0;
while(li<r&&lt>=0)
{
cn[lt]++;
if(s[++li]=='(')lt++;
else lt--;
}
int ri=r+1,rt=0;
while(ri>l&&rt>=0)
{
if(li==ri)
{
if(s[li--]=='(')lt--;
else lt++;
cn[lt]--;
}
res+=cn[rt];
if(s[--ri]==')')rt++;
else rt--;
}
while(li>=l)
{
if(s[li--]=='(')lt--;
else lt++;
cn[lt]--;
}
printf("%lld\n",res);
}
return 0;

设\(f[l][r]\)表示区间\([l,r]\)的方案数

考虑类似\(S[l,r]\)形如\((...)\)的询问,\(l'\)为\(s[l]\)匹配右括号的位置,\(r'\)为\(s[r]\)匹配左括号的位置,我们对删去\(L,R\)位置进行讨论

\(Sit_1:L>l'\)或\(R<r'\)

\(Case_1:L>l'\)且\(R<r'\) \(f[l][r]+=f[l'+1][r'-1]\)比较显然,可以和外面的合法括号序列接上

\(Case_2:R<r',f[l][r]+=f[l][r'-1]\),同上

\(Case_3:L>l' ,f[l][r]+=f[l'+1][r]\),同上

\(Sit_2:L\leq l',R\geq r'\)

\(f[l][r]+=f[l+1][r-1]\)

至于不是形如这样的询问,直接把\(l'=n,r'=1\)即可

正确性的话,这样的话转移的时候不合法的就直接变成\(0\)了,就是包含最左最右不合法部分的

#include<bits/stdc++.h>
#define MAXN 8010
using namespace std;
int n,q,in1,in2,pre[MAXN],nxt[MAXN],dp[MAXN][MAXN];
vector<int>sta;
char s[MAXN];
int main()
{
scanf("%d%d",&n,&q);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
pre[i]=1;//r'
nxt[i]=n;//l'
}
for(int i=1;i<=n;i++)
{
if(s[i]=='(')
{
sta.push_back(i);
}
else
{
if(!sta.empty())
{
nxt[sta.back()]=i;
sta.pop_back();
}
}
} sta.clear();
for(int i=n;i;i--)
{
if(s[i]==')')
{
sta.push_back(i);
}
else
{
if(!sta.empty())
{
pre[sta.back()]=i;
sta.pop_back();
}
}
}
sta.clear();
for(int i=1;i<=n;i++)dp[i][i]=1;
for(int i=1;i<n;i++)
{
for(int j=1;j+i<=n;j++)
{
dp[j][j+i]=dp[nxt[j]+1][j+i]+dp[j][pre[j+i]-1]-dp[nxt[j]+1][pre[j+i]-1]+1;
// cout<<"zy: "<<nxt[j]+1<<" "<<j+i<<"\n";
// cout<<"zy: "<<j<<" "<<pre[j+i]-1<<"\n";
// cout<<"zy: "<<nxt[j]+1<<" "<<pre[j+i]-1<<"\n";
if(s[j]=='('&&s[j+i]==')')
{
dp[j][j+i]+=dp[j+1][j+i-1];
}
}
}
for(int i=1,l,r;i<=q;i++)
{
scanf("%d%d",&l,&r);
cout<<dp[l][r]<<"\n";
}
return 0;
}

\(T2\)泽连斯基

——那是,至今为止都不曾体会的懵懂

\(l_i\le r_i\)的部分分比较简单,考虑维护一个单点最大值就好了,因为必然有一个位置被所有线段包含

正解:

考虑枚举一个圆弧,钦定为答案中最短的圆弧为\(x\)

可以把其余圆弧分成\(7\)类

\(Case_1:\)和\(x\)相同,必然需要加入答案

\(Case_2:\)被\(x\)包含,钦定\(x\)最小,必然不选

\(Case_3:\)包含\(x\),由于\(x\)和其他有交,那么包含\(x\)必然也有交,必然加入答案

\(Case_4:\)和\(x\)无交,必然不选

\(Case_5:\)包含\(x\)左端点,称为\(L\),下面讨论

\(Case_6:\)包含\(x\)右端点,称为\(R\),下面讨论

\(Case_7:\)包含左右\(x\)端点,但不包含\(x\),称为\(U\),\(U\)必然与\(L/R\)相交,\(U\)必选

我们只需考虑\(L,R\)最多可以选出几个,\(L,R\)内部必然两两相交

所以我们二维数点!

圆弧看成平面上一个点\((x,y)\),\(L\)为黑点,\(R\)为白点,转化成

平面上选出最多的点使得不存在一个黑点\((x_1,y_1)\)和一个白点\((x_2,y_2)\)满足\(x_1<y_1\land x_2<y_2\)

然后考虑\(dp\),\(f[x][y]\)表示横坐标\(\leq x\)的所有点,黑点纵坐标最小值为\(y\)最多能选多少个,由于最大值我们直接选一个最大值转移就好了,这就变成了一个线段树优化\(DP\)

#include <bits/stdc++.h>
//#define int long long
#define ll long long
#define db double
#define fi first
#define se second
#define pii pair<int,int>
#define vi vector<int> using namespace std;
const int maxn=6e3;
struct node {
int l,r;
} a[maxn+5];
int n,L[maxn+5],R[maxn+5],key[maxn*2+5],cnt,cnt2; int ID[maxn+5],len[maxn+5];
int in(int l,int r,int x) {
if (l<=r) return l<=x && x<=r;
return ((l<=x && x<=cnt) || (1<=x && x<=r));
}
struct point {
int x,y,o;
point() {
x=y=o=0;
}
point(int a,int b,int c) {
x=a,y=b,o=c;
}
bool operator < (const point &t) const {
return x==t.x?(o>t.o):x<t.x;
}
} b[maxn+5];
int num; int mx[maxn*8+5],tag[maxn*8+5];
void seta(int p,int d) {
tag[p]+=d;
mx[p]+=d;
}
void upd(int p) {
mx[p]=max(mx[p+p],mx[p+p+1]);
}
void push(int p) {
if (!tag[p]) return ;
seta(p+p,tag[p]);
seta(p+p+1,tag[p]);
tag[p]=0;
}
void build(int p,int l,int r) {
mx[p]=-1e9;
tag[p]=0;
if (l==r) {
if (l==cnt2) mx[p]=0;
return ;
}
int mid=(l+r)>>1;
build(p+p,l,mid);
build(p+p+1,mid+1,r);
upd(p);
}
void modify(int p,int l,int r,int ql,int qr,int d) {
if (ql>qr) return ;
if (l==ql&&r==qr) {
seta(p,d);
return ;
}
int mid=(l+r)>>1;
push(p);
if (qr<=mid) modify(p+p,l,mid,ql,qr,d);
else if (mid<ql) modify(p+p+1,mid+1,r,ql,qr,d);
else modify(p+p,l,mid,ql,mid,d),modify(p+p+1,mid+1,r,mid+1,qr,d);
upd(p);
}
void cover(int p,int l,int r,int pos,int d) {
if (l==r){
mx[p]=max(mx[p],d);
return ;
}
push(p);
int mid=(l+r)>>1;
if (pos<=mid) cover(p+p,l,mid,pos,d);
else cover(p+p+1,mid+1,r,pos,d);
upd(p);
}
int query(int p,int l,int r,int ql,int qr) {
if (ql>qr) return -1e9;
if (l==ql&&r==qr) return mx[p];
int mid=(l+r)>>1;
push(p);
if (qr<=mid) return query(p+p,l,mid,ql,qr);
else if (mid<ql) return query(p+p+1,mid+1,r,ql,qr);
else return max(query(p+p,l,mid,ql,mid),query(p+p+1,mid+1,r,mid+1,qr));
} void solve() {
cin>>n;
cnt=0;
for (int i=1;i<=n;i++) {
cin>>L[i]>>R[i];
key[++cnt]=L[i],key[++cnt]=R[i];
}
sort(key+1,key+cnt+1);
cnt=unique(key+1,key+cnt+1)-key-1;
for (int i=1;i<=n;i++) {
L[i]=lower_bound(key+1,key+cnt+1,L[i])-key;
R[i]=lower_bound(key+1,key+cnt+1,R[i])-key;
len[i]=(R[i]-L[i]+cnt)%cnt;
}
for (int i=1;i<=cnt;i++) ID[i]=0;
int ans=0;
for (int i=1;i<=n;i++) {
num=cnt2=0;
int nl=L[i],nr=R[i];
int p=nl;
while (1) {
ID[p]=i;
if (p==nr) break ;
p=p%cnt+1;
}
int cursum=0;
for (int j=1;j<=n;j++) {
if (i==j) continue ;
if (len[j]<len[i]) {
continue ;
}
int inl=in(L[j],R[j],L[i]);
int inr=in(L[j],R[j],R[i]);
if (!inl && !inr) continue ;
if (inl && inr) cursum++;
else {
int x=L[j],y=R[j];
if (ID[x]!=i) swap(x,y);
x=(x-L[i]+cnt)%cnt;
y=(L[i]-y+cnt)%cnt;
x++,y++;
if (inl) {
b[++num]=point(x,y,0);
key[++cnt2]=y;
}
else {
b[++num]=point(x,y,1);
key[++cnt2]=y;
}
}
}
if (!num) {
ans=max(ans,cursum+1);
continue;
}
sort(key+1,key+cnt2+1);
cnt2=unique(key+1,key+cnt2+1)-key-1;
for (int j=1;j<=num;j++) {
b[j].y=lower_bound(key+1,key+cnt2+1,b[j].y)-key;
}
build(1,1,cnt2);
sort(b+1,b+num+1);
for (int j=1;j<=num;j++) {
if (b[j].o==0) {
modify(1,1,cnt2,1,b[j].y-1,1);
int mx=query(1,1,cnt2,b[j].y,cnt2);
cover(1,1,cnt2,b[j].y,mx+1);
}
else {
modify(1,1,cnt2,b[j].y,cnt2,1);
}
}
ans=max(ans,cursum+mx[1]+1);
}
cout<<ans<<'\n';
}
int main() { int T;
cin>>T;
while (T--) solve();
return 0;
}

\(T3\)​

——那是,将我们三色交织在一起的绘卷

不会

讲题人:这道题太奇怪了,咱们不讲了吧

魔怔出题人的题解

6.6 NOI 模拟的更多相关文章

  1. 5.30 NOI 模拟

    $5.30\ NOI $模拟 高三大哥最后一次模拟考了,祝他们好运 \(T1\)装箱游戏 显然可以将四种字母之间的空缺当做状态枚举 那么这道题就很显然了 #include<bits/stdc++ ...

  2. 5.23 NOI 模拟

    $5.23\ NOI $模拟 \(T1\)简单的计算几何题 \(zjr:\)我当时没改,那么自己看题解吧 倒是有个简单的随机化方法(能获得\(72pts,\)正确性未知)\(:\) 随机两条切椭圆的平 ...

  3. 5.6 NOI模拟

    \(5.6\ NOI\)模拟 明天就母亲节了,给家里打了个电话(\(lj\ hsez\)断我电话的电,在宿舍打不了,只能用教练手机打了) 其实我不是很能看到自己的\(future,\)甚至看不到高三的 ...

  4. 5.4 NOI模拟

    \(5.4\ NOI\)模拟 \(T1\) 想到分讨,但是暴力输出一下方案之后有很多特别的情况要讨论,就弃了... 假设\(a\)是原序列,\(b\)是我们得到的序列 设\(i\)是最长公共前缀,\( ...

  5. NOI模拟赛 Day1

    [考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...

  6. NOI 模拟赛 #2

    得分非常惨惨,半个小时写的纯暴力 70 分竟然拿了 rank 1... 如果 OYJason 和 wxjor 在可能会被爆踩吧 嘤 T1 欧拉子图 给一个无向图,如果一个边集的导出子图是一个欧拉回路, ...

  7. 【2018.12.10】NOI模拟赛3

    题目 WZJ题解 大概就是全场就我写不过 $FFT$ 系列吧……自闭 T1 奶一口,下次再写不出这种 $NTT$ 裸题题目我就艹了自己 -_-||| 而且这跟我口胡的自创模拟题 $set1$ 的 $T ...

  8. 6.28 NOI模拟赛 好题 状压dp 随机化

    算是一道比较新颖的题目 尽管好像是两年前的省选模拟赛题目.. 对于20%的分数 可以进行爆搜,对于另外20%的数据 因为k很小所以考虑上状压dp. 观察最后答案是一个连通块 从而可以发现这个连通块必然 ...

  9. NOI模拟赛Day5

    T1 有and,xor,or三种操作,每个人手中一个数,求和左边进行某一种运算的最大值,当t==2时,还需要求最大值的个数. test1 20% n<=1000 O(n^2)暴力 test2 2 ...

  10. NOI模拟赛Day4

    看到成绩的时候我的内心** woc第一题写错了呵呵呵呵呵呵呵呵 人不能太浪,会遭报应的** ------------------------------------------------------ ...

随机推荐

  1. 个人冲刺(二)——体温上报app(二阶段)

    冲刺任务:完成app首页.第二页面和特殊情况的页面布局 activity_main.xml <?xml version="1.0" encoding="utf-8& ...

  2. Spring Boot中的微信支付(小程序)

    前言 微信支付是企业级项目中经常使用到的功能,作为后端开发人员,完整地掌握该技术是十分有必要的. logo 一.申请流程和步骤 图1-1 注册微信支付账号 获取微信小程序APPID 获取微信商家的商户 ...

  3. React简单教程-4.1-hook

    前言 虽然我们简单感受了一下 useState 的用法,但我想你还是对 React 里的 hook 迷迷糊糊的.本文我们将明确下 React 的概念. HOOK 前生今世 在我示例中,写的 React ...

  4. mybatis-plus对空字段 时间进行填充

    package com.tanhua.sso.handler; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; imp ...

  5. nginx转发rabbitmq

    第一种: 直接加个location块 location /rabbitmq/ { proxy_pass http://127.0.0.1:15672/; } 第二种: location /rabbit ...

  6. Java中时间方法大全01(持续更新)

    下面这些方法都可以封装到一个工具类中 /** * 获取当前时间的时间戳 */ public static int getCurrentTimeIntValue() { return (int) (Sy ...

  7. NC20806 区区区间间间

    NC20806 区区区间间间 题目 题目描述 给出长度为n的序列a,其中第i个元素为 \(a_i\),定义区间(l,r)的价值为 \(v_{l,r} = max(a_i - a_j | l \leqs ...

  8. 纪念我逝去的n个小时

    纪念我逝去的n个小时 某人的惨案要我擦屁股=.= #include <bits/stdc++.h> using namespace std; template<class T> ...

  9. 记一次 .NET 某工控数据采集平台 线程数 爆高分析

    一:背景 1. 讲故事 前几天有位朋友在 B站 加到我,说他的程序出现了 线程数 爆高的问题,让我帮忙看一下怎么回事,截图如下: 说来也奇怪,这些天碰到了好几起关于线程数无缘无故的爆高,不过那几个问题 ...

  10. 一题多解,ASP.NET Core应用启动初始化的N种方案[上篇]

    ASP.NET Core应用本质上就是一个由中间件构成的管道,承载系统将应用承载于一个托管进程中运行起来,其核心任务就是将这个管道构建起来.在ASP.NET Core的发展历史上先后出现了三种应用承载 ...