zoukankan      html  css  js  c++  java
  • [BZOJ4881][Lydsy1705月赛]线段游戏

    首先冷静一下看清问题的本质,是将整个数列分成两个递增子序列。

    那么由Dilworth定理得,无解当且仅当数列的最长下降子序列的长度>2,先特判掉。

    然后就有一些比较厉害的做法:http://www.cnblogs.com/Gloid/p/10025835.html

    一种比较直观的做法是,将每对逆序对连边,答案就是连通块的个数。

    考虑优化这个暴力,从前往后处理,每个连通块用块内最大的数作为代表,用set维护代表。每次加入一个数时,将set中所有大于这个数的数都删去(这些数代表的连通块合并了),然后将最大的那个放进去(新的大连通块的代表)。

     1 #include<set>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=100010,mod=998244353;
     8 int n,ans,tot,a[N],f[N];
     9 set<int>S;
    10 
    11 int find(int x){
    12     int L=1,R=tot;
    13     while (L<R){
    14         int mid=(L+R)>>1;
    15         if (x<=f[mid]) L=mid+1; else R=mid;
    16     }
    17     return L;
    18 }
    19 
    20 int main(){
    21     freopen("bzoj4881.in","r",stdin);
    22     freopen("bzoj4881.out","w",stdout);
    23     scanf("%d",&n);
    24     rep(i,1,n) scanf("%d",&a[i]);
    25     f[1]=a[1]; tot=1;
    26     rep(i,2,n){
    27         if (a[i]<f[tot]){
    28             tot++,f[tot]=a[i];
    29             if (tot>2){ puts("0"); return 0; }
    30         }else{
    31             int t=find(a[i]); f[t]=max(f[t],a[i]);
    32         }
    33     }
    34     rep(i,1,n){
    35         int t=a[i];
    36         while (!S.empty()){
    37             set<int>::iterator it=S.upper_bound(t);
    38             if (it==S.end()) break;
    39             t=*it; S.erase(t);
    40         }
    41         S.insert(t);
    42     }
    43     tot=S.size(); ans=1;
    44     rep(i,1,tot) ans=2ll*ans%mod;
    45     printf("%d
    ",ans);
    46     return 0;
    47 }
  • 相关阅读:
    It is unuseful to regret
    越难熬的时候,越要靠自己
    2019/11/11
    QT Http
    QT 初步认识
    模板
    RTTI(Runtime Type Infomation)
    位域
    C++ 多字节string转UTF-8 string
    C++ 读写csv文件
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10122958.html
Copyright © 2011-2022 走看看