zoukankan      html  css  js  c++  java
  • [家里训练20_03_01]ABC

    1.不可做题。

    求出满足
    $$sum_{i=1}^{m}{x_i}leq s$$
    对任意$$ileq m,x_i>0$$
    对所有$$i,x_ileq t$$
    的解数
    答案对10^9+7取模
    m-n<=1000,t<=100000,m<=1E9,nt<=s<=1E18

    2.树上LIS:一棵树,点权是一个排列。选出最多的点,使得每一个被选中的点,子树中没有比这个点权更大的点。

    对于每个点,维护当前答案集合。这个集合的意义是,将元素从小到大排序,第i个元素的值表示能够选出恰好i的点的最小权值是多少。每次转移时,尝试将比当前值更大且最小的值删去,并加入集合中,可见这就是一个启发式合并。虽然无法知道具体的方案,但能算出个数。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=2E5+5;
     4 int n,tot,ans,val[maxn];
     5 int size,head[maxn];
     6 multiset<int>S[maxn];
     7 struct edge
     8 {
     9     int to,next;
    10 }E[maxn*2];
    11 inline void add(int u,int v)
    12 {
    13     E[++size].to=v;
    14     E[size].next=head[u];
    15     head[u]=size;
    16 }
    17 void dfs(int u)
    18 {
    19     for(int i=head[u];i;i=E[i].next)
    20     {
    21         int v=E[i].to;
    22         dfs(v);
    23         if(S[u].size()>S[v].size())
    24             swap(S[u],S[v]);
    25         for(multiset<int>::iterator pt=S[v].begin();pt!=S[v].end();++pt)
    26             S[u].insert(*pt);
    27     }
    28     multiset<int>::iterator pt=S[u].lower_bound(val[u]);
    29     if(pt!=S[u].end())
    30         S[u].erase(pt);
    31     S[u].insert(val[u]);
    32 }
    33 int main()
    34 {
    35     freopen("tree.in","r",stdin);
    36     freopen("tree.out","w",stdout);
    37     ios::sync_with_stdio(false);
    38     cin>>n;
    39     for(int i=1;i<=n;++i)
    40     {
    41         int x,y;
    42         cin>>x>>y;
    43         val[i]=x;
    44         if(y!=0)
    45             add(y,i);
    46     }
    47     dfs(1);
    48     cout<<S[1].size()<<endl;
    49     return 0;
    50 }
    View Code

    3.有三个n排列a,b,c,求出有多少合法的三元组。合法的定义为,存在一个下标集合,使得$(x,y,z)=(max_{i∈S}a_i,max_{i∈S}b_i,max_{i∈S}c_i)$。

    可以发现,有很多无用的下标集合。我们现在只考虑所有合法三元组的“最小表示”,即它的下标集合中没有冗余的信息。可以证明,两者是一一对应的。

    对于所有可能的情况,下标集合的大小为1或2或3。若大小为1,贡献为n。若大小为2,表明这个集合的两个位置上存在两种最大值。若大小为3,则三个位置上有三种最大值。

    对于大小为2的下标集合,考虑容斥。不合法的集合的个数,即为一个位置上所有数字都对应大于另一个位置的集合的个数,这显然是一个三位偏序问题。

    对于大小为3的下标集合,考虑容斥。方便起见,记(x,y,z)表示三个位置上分别有x,y,z种最大值(不考虑顺序)。(3,0,0)显然也是个三位偏序。要统计(2,1,0),我们假设2的位置上存在一个a排列中的最大值。我们先对a排序,对于b排列,统计前面有多少数字大于当前位置的b排列上的数字。算完后(对a,b,c排列都算了一遍),统计了3次(3,0,0),3次(2,1,0),(3,0,0)可以由前面的结果减去,就得到了(2,1,0)的个数

    复杂度nlog^2n。

      1 #pragma GCC optimize 2
      2 #include<bits/stdc++.h>
      3 using namespace std;
      4 typedef long long int ll;
      5 const int maxn=2E5+5;
      6 ll n,tot,ans[maxn];
      7 int A[maxn],B[maxn],C[maxn];
      8 int where[maxn],tmp[maxn];
      9 struct pt
     10 {
     11     int a,b,c;
     12 }a[maxn];
     13 inline bool cmpA(const pt&A,const pt&B)
     14 {
     15     return A.a<B.a;
     16 }
     17 inline bool cmpB(const pt&A,const pt&B)
     18 {
     19     return A.b<B.b;
     20 }
     21 struct BIT
     22 {
     23     ll t[maxn];
     24     inline int lowbit(int x)
     25     {
     26         return x&(-x);
     27     };
     28     inline void add(int x,ll y)
     29     {
     30         while(x<=n)
     31         {
     32             t[x]+=y;
     33             x+=lowbit(x);
     34         }
     35     }
     36     inline void set(int x,int y)
     37     {
     38         while(x<=n)
     39         {
     40             t[x]=y;
     41             x+=lowbit(x);
     42         }
     43     }
     44     inline ll ask(int x)
     45     {
     46         ll sum=0;
     47         while(x)
     48         {
     49             sum+=t[x];
     50             x-=lowbit(x);
     51         }
     52         return sum;
     53     }
     54     inline void clear()
     55     {
     56         memset(t,0,sizeof(t));
     57     }
     58 }T;
     59 void cdq(int l,int r)
     60 {
     61     if(l==r)
     62         return;
     63     int mid=(l+r)>>1;
     64     cdq(l,mid),cdq(mid+1,r);
     65     int i=l,j=mid+1,k=l;
     66     while(k<=r)
     67     {
     68         if(j>r||(i<=mid&&a[where[i]].b<a[where[j]].b))
     69         {
     70             T.add(a[where[i]].c,1);
     71             tmp[k++]=where[i++];
     72         }
     73         else
     74         {
     75             ll x=T.ask(a[where[j]].c);
     76             ans[where[j]]+=x;
     77             tmp[k++]=where[j++];
     78         }
     79     }
     80     for(int i=l;i<=mid;++i)
     81         T.set(a[where[i]].c,0);
     82     for(int i=l;i<=r;++i)
     83         where[i]=tmp[i];
     84 }
     85 inline ll get1()
     86 {
     87     return n;
     88 }
     89 inline bool check(pt a,int x,int y,int z)
     90 {
     91     return a.a==x||a.b==y||a.c==z;
     92 }
     93 inline ll get2()
     94 {
     95     ll sum=n*(n-1)/2;
     96     for(int i=1;i<=n;++i)
     97         sum-=ans[i];
     98     return sum;
     99 }
    100 inline ll get3()
    101 {
    102     ll sum=n*(n-1)*(n-2)/6;
    103     sort(a+1,a+n+1,cmpA);
    104     T.clear();
    105     for(int i=1;i<=n;++i)
    106     {
    107         ll x=T.ask(a[i].b-1);
    108         sum-=x*(x-1)/2;
    109         T.add(a[i].b,1);
    110     }
    111     T.clear();
    112     for(int i=1;i<=n;++i)
    113     {
    114         ll x=T.ask(a[i].c-1);
    115         sum-=x*(x-1)/2;
    116         T.add(a[i].c,1);
    117     }
    118     sort(a+1,a+n+1,cmpB);
    119     T.clear();
    120     for(int i=1;i<=n;++i)
    121     {
    122         ll x=T.ask(a[i].c-1);
    123         sum-=x*(x-1)/2;
    124         T.add(a[i].c,1);
    125     }
    126     for(int i=1;i<=n;++i)
    127         sum+=ans[i]*(ans[i]-1);
    128     return sum;
    129 }
    130 inline void solve()
    131 {
    132     for(int i=1;i<=n;++i)
    133         a[i]=(pt){A[i],B[i],C[i]},where[i]=i;
    134     sort(a+1,a+n+1,cmpA);
    135     cdq(1,n);
    136     cout<<get1()+get2()+get3()<<endl;
    137 }
    138 int main()
    139 {
    140     freopen("subset.in","r",stdin);
    141     freopen("subset.out","w",stdout);
    142     ios::sync_with_stdio(false);
    143     cin>>n;
    144     for(int i=1;i<=n;++i)
    145         cin>>A[i];
    146     for(int i=1;i<=n;++i)
    147         cin>>B[i];
    148     for(int i=1;i<=n;++i)
    149         cin>>C[i];
    150     solve();
    151     return 0;
    152 }
    View Code
  • 相关阅读:
    【BZOJ】4636: 蒟蒻的数列
    BZOJ1878 [SDOI2009]HH的项链
    【网络流24题----02】太空飞行计划
    【网络流24题----03】Air Raid最小路径覆盖
    【网络流24题----01】飞行员配对方案问题
    素数判定(米勒测试定理-费马小定理+快速乘)
    一堆模板(丑陋0.0)------数据结构
    丑数(USACO)
    NOI[2001]食物链
    关于Tarjan(2)
  • 原文地址:https://www.cnblogs.com/GreenDuck/p/12456678.html
Copyright © 2011-2022 走看看