BZOJ4881 [Lydsy2017年5月月赛]线段游戏
2017-05-15 21:12
363 查看
观察一下题意就是让你把排列分成两个没有逆序的序列,问方案数
那么把每个逆序对连边,容易发现如果是二分图,答案就是2^(联通块数量),否则无解
那么先把无解判掉,然后从前往后一个数一个数加入,因为现在肯定有解了,所以对于同一个i和a[i],任意两个满足j<i,a[j]>a[i]的j和j',j和j'当前一定属于两个不同的联通块,而现在他们都要和i连边,那么把i加进来之后他们就都变成一个联通块了
而对于一个联通块,我们只需要保存其中最大的元素就可以,因为第二大的元素永远也不会再向后连边了,如果第二大的还能向后连边就说明无解
那么从前往后扫一遍,每次加一个数之后把大于等于这个数的都删掉,再把删掉的数里最大的加回来
最后剩的数的个数就是联通块的数量
#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 100010
#define MAXM 1010
#define ll long long
#define eps 1e-8
#define MOD 998244353
#define INF 1000000000
#define lb(x) x&-x
set<int>s;
int c[MAXN];
int ans=1;
int n;
int ask(int x){
int re=0;
for(;x;x-=lb(x)){
re=max(re,c[x]);
}
return re;
}
void change(int x,int y){
for(;x<=n;x+=lb(x)){
c[x]=max(c[x],y);
}
}
int main(){
int i,x;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&x);
int t=ask(n-x);
if(t==2){
printf("0\n");
return 0;
}
change(n-x+1,t+1);
int mx=x;
set<int>::iterator p=s.upper_bound(x);
while(p!=s.end()){
mx=max(mx,*p);
set<int>::iterator tmp=p;
p++;
s.erase(tmp);
}
s.insert(mx);
}
x=s.size();
while(x){
(ans<<=1)%=MOD;
x--;
}
printf("%d\n",ans);
return 0;
}
/*
*/
那么把每个逆序对连边,容易发现如果是二分图,答案就是2^(联通块数量),否则无解
那么先把无解判掉,然后从前往后一个数一个数加入,因为现在肯定有解了,所以对于同一个i和a[i],任意两个满足j<i,a[j]>a[i]的j和j',j和j'当前一定属于两个不同的联通块,而现在他们都要和i连边,那么把i加进来之后他们就都变成一个联通块了
而对于一个联通块,我们只需要保存其中最大的元素就可以,因为第二大的元素永远也不会再向后连边了,如果第二大的还能向后连边就说明无解
那么从前往后扫一遍,每次加一个数之后把大于等于这个数的都删掉,再把删掉的数里最大的加回来
最后剩的数的个数就是联通块的数量
#include<iostream>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<cstdio>
#include<map>
#include<bitset>
#include<set>
#include<stack>
#include<vector>
#include<queue>
using namespace std;
#define MAXN 100010
#define MAXM 1010
#define ll long long
#define eps 1e-8
#define MOD 998244353
#define INF 1000000000
#define lb(x) x&-x
set<int>s;
int c[MAXN];
int ans=1;
int n;
int ask(int x){
int re=0;
for(;x;x-=lb(x)){
re=max(re,c[x]);
}
return re;
}
void change(int x,int y){
for(;x<=n;x+=lb(x)){
c[x]=max(c[x],y);
}
}
int main(){
int i,x;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&x);
int t=ask(n-x);
if(t==2){
printf("0\n");
return 0;
}
change(n-x+1,t+1);
int mx=x;
set<int>::iterator p=s.upper_bound(x);
while(p!=s.end()){
mx=max(mx,*p);
set<int>::iterator tmp=p;
p++;
s.erase(tmp);
}
s.insert(mx);
}
x=s.size();
while(x){
(ans<<=1)%=MOD;
x--;
}
printf("%d\n",ans);
return 0;
}
/*
*/
相关文章推荐
- bzoj 4881: [Lydsy2017年5月月赛]线段游戏 树状数组+set
- [bzoj4881][Lydsy2017年5月月赛]线段游戏
- BZOJ4881: [Lydsy2017年5月月赛]线段游戏
- 【bzoj4881】[Lydsy2017年5月月赛]线段游戏 树状数组+STL-set
- BZOJ 4881: [Lydsy2017年5月月赛]线段游戏
- 4881: [Lydsy2017年5月月赛]线段游戏
- BZOJ 4881 [Lydsy2017年5月月赛] 二分图染色+线段树
- bzoj 4886: [Lydsy2017年5月月赛]叠塔游戏 并查集
- bzoj4881: [Lydsy2017年5月月赛]线段游戏
- bzoj4886 [Lydsy2017年5月月赛]叠塔游戏
- 【BZOJ4881】5月月赛D 线段游戏 树状数组+set
- bzoj4878: [Lydsy2017年5月月赛]挑战NP-Hard
- 【BZOJ4883】[Lydsy2017年5月月赛]棋盘上的守卫 KM算法
- BZOJ 4883 [Lydsy2017年5月月赛]棋盘上的守卫(最小生成环套树森林)
- bzoj4879: [Lydsy2017年5月月赛]失控的数位板
- bzoj5049 [Lydsy2017年5月月赛]导航系统
- bzoj4885: [Lydsy2017年5月月赛]长方体
- BZOJ4886 [Lydsy2017年5月月赛]叠塔游戏
- BZOJ4883 [Lydsy2017年5月月赛]棋盘上的守卫
- 【bzoj4883】[Lydsy2017年5月月赛]棋盘上的守卫 最小环套树森林