\(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. data:image字符转byte[]

    var data = "data:image/bmp;base64,Qk3aHwAAAAAAADYAAAAoAAAAZAAAABsAAAABABgAAAAAAKQfAAAAAQAAAAEAA ...

  2. 796. Rotate String - LeetCode

    Question 796. Rotate String Solution 题目大意:两个字符串匹配 思路:Brute Force Java实现: public boolean rotateString ...

  3. [C++STL] 迭代器 iterator 的使用

    定义 迭代器是一种检查容器内元素并遍历元素的数据类型,表现的像指针. 基本声明方式 容器::iterator it = v.begin();//例:vector<int>::iterato ...

  4. 拥有webkit内核浏览器的平台

    1-拥有webkit内核的浏览器: IOS safari Android 的浏览器 Google chrome 猎豹浏览器 百度浏览器 Opera 以上可知手机的浏览器均为webkit内核 2-拥有其 ...

  5. java提前工作、第一个程序

    java提前工作 我们学习编程肯定会 运用到相应的软件 在这里 我个人推荐 eclipse.idea 这里的软件呢 都是用我们的java编程出来的,那它也需要用java来支持他的开发环境 这里就运用到 ...

  6. 修改SQL Server用户的密码-使用SSMS

    更新日志 2022年6月13日 发布文章. 2022年5月21日 开始文章. 打开软件Microsoft SQL Server Management Studio(简写:SSMS). 登录连接具体的数 ...

  7. C#项目中常见的目录和文件

    本文迁移自Panda666原博客,原发布时间:2021年4月17日. Bin 目录 bin是英文binary的缩写, 字面意思是二进制,意指用来存放编译后的结果.C#/VB编译器编译后的程序二进制文件 ...

  8. 27.MySQL 索引、事务与存储引擎

    MySQL 索引.事务与存储引擎 目录 MySQL 索引.事务与存储引擎 MySQL 索引 索引的概念 索引的作用及副作用 索引的作用 索引的副作用 创建索引的原则依据 索引的分类和创建 普通索引 唯 ...

  9. pyenv安装及使用教程

    pyenv安装及使用教程 pyenv 安装 git clone https://github.com/pyenv/pyenv.git ~/.pyenv # 编辑 bashrc vim ~/.bashr ...

  10. JavaScript中用画布canvans做贪吃蛇

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...