[bzoj4881]线段游戏
来源:互联网 发布:js手机上下滑动事件 编辑:程序博客网 时间:2024/05/29 11:35
题目描述
quailty和tangjz正在玩一个关于线段的游戏。在平面上有n条线段,编号依次为1到n。其中第i条线段的两端点坐
标分别为(0,i)和(1,p_i),其中p_1,p_2,…,p_n构成了1到n的一个排列。quailty先手,他可以选择一些互不相交
的线段,将它们拿走,当然他也可以一条线段也不选。然后tangjz必须拿走所有剩下的线段,若有两条线段相交,
那么他就输了,否则他就赢了。注意若quailty拿走了全部线段,那么tangjz也会胜利。quailty深深喜欢着tangjz
,所以他不希望tangjz输掉游戏,请计算他有多少种选择线段的方式,使得tangjz可以赢得游戏。
DP
相当于走出两条路线,将所有数包含,使得每条路线都是单调增的。
为了方便我们加入p[0]=0和p[n+1]=n+1。
设f[i]表示一条路线(没有指定是第一条路线)走到了i-1,另一条路线走到了i,满足条件的方案数。
边界是f[1]=1,答案是f[n+1]*2(两条路线实际上不可区分但原题中可区分那么它们可以交换即乘2)。
如何转移呢?在i的路线会包含一段区间[i,j],而不包含j+1,则j+1被处在i-1的路线包含,然后就可以转移到f[j+1]。
需要满足的条件是[i,j]单增,
可以预处理next[i]表示最大的j满足[i,j]单增,next数组有单调性。
那么这就是暴力dp了。
优化
我们按顺序扫。
当我们做出f[i]后,接下来可以转移到的j必须满足
而可以转移到的j还要满足
得到一个f[i]可以直接在线段树中找到p[i]这个位置。
复杂度n log n。
#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=100000+10,mo=998244353;int ad[maxn*4];int h[maxn],go[maxn],nxt[maxn];int ask[maxn][3];int id[maxn],a[maxn],next[maxn],f[maxn];int i,j,k,l,t,n,m,tot,top;int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){ if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*f;}void add(int x,int y){ go[++tot]=y; nxt[tot]=h[x]; h[x]=tot;}void mark(int p,int v){ (ad[p]+=v)%=mo;}void down(int p){ if (ad[p]){ mark(p*2,ad[p]); mark(p*2+1,ad[p]); ad[p]=0; }}void change(int p,int l,int r,int a,int b,int v){ if (l==a&&r==b){ mark(p,v); return; } down(p); int mid=(l+r)/2; if (b<=mid) change(p*2,l,mid,a,b,v); else if (a>mid) change(p*2+1,mid+1,r,a,b,v); else{ change(p*2,l,mid,a,mid,v); change(p*2+1,mid+1,r,mid+1,b,v); }}int query(int p,int l,int r,int a){ if (l==r) return ad[p]; down(p); int mid=(l+r)/2; if (a<=mid) return query(p*2,l,mid,a);else return query(p*2+1,mid+1,r,a);}int main(){ n=read(); fo(i,1,n) a[i]=read(); a[0]=0;a[n+1]=n+1; fd(i,n,1){ if (i<n&&a[i]<a[i+1]) next[i]=next[i+1]; else next[i]=i; } f[1]=1; fo(i,1,n+1){ t=h[i]; while (t){ change(1,0,n+1,ask[go[t]][0],ask[go[t]][1],-ask[go[t]][2]); t=nxt[t]; } if (i>1) f[i]=query(1,0,n+1,a[i]); if (i>n) break; top++; ask[top][0]=a[i-1]+1; ask[top][1]=n+1; ask[top][2]=f[i]; add(next[i]+2,top); change(1,0,n+1,a[i-1]+1,n+1,f[i]); } (f[n+1]+=mo)%=mo; printf("%d\n",f[n+1]*2%mo);}
- [bzoj4881]线段游戏
- bzoj4881: [Lydsy2017年5月月赛]线段游戏
- BZOJ4881 [Lydsy2017年5月月赛]线段游戏
- BZOJ4881: [Lydsy2017年5月月赛]线段游戏
- bzoj4881 [ Lydsy2017年5月月赛 ] -- 二分图染色+线段树
- 【BZOJ4519】【Sdoi2016】游戏 线段树
- codeforces366(线段树,博弈游戏)
- POJ2886线段树 Joseph游戏(单点更新)
- Bzoj 4515 线段树 SDOI2016 游戏 Game
- 【bzoj4515】【SDOI2016】【游戏】【线段树+树链剖分】
- 色板游戏(线段树)
- bzoj 4515: [Sdoi2016]游戏 树链剖分+线段树
- poj2777 色板游戏(线段树)
- 【BZOJ4515】游戏,树链剖分+永久化标记线段树维护线段信息(李超线段树)
- [树链剖分 线段树 标记永久化] BZOJ 4515 [Sdoi2016]游戏
- JZOJ4686 卡牌游戏 线段树维护贪心策略
- jzoj 4684. 【GDOI2017模拟8.11】卡牌游戏 线段树
- bzoj 4515: [Sdoi2016]游戏(树链剖分+线段树)
- 关于如何写代码和学习代码
- 这是一个完全Made in China的炫酷弹出指示层
- Java 面向对象
- php 中return、exit()、die()用法比较
- linux命令
- [bzoj4881]线段游戏
- 三种网页抓取方法性能对比
- java多态向上转型和向下转型
- C#连接数据库简单点的,可以当成一个模板
- 2017年暑假实习面经: 去哪儿网(一面, 二面, HR面, Offer), 腾讯IEG(一面, GG...), 百度(一面, 二面, 三面, offer)
- java基础--5.集合-4.Collection接口
- ios审核被拒、提示ipv6、实际是阿里云OSS的问题
- redis高性能SDS字符串实现
- lintcode(603)Largest Divisible Subset