随笔- 109  文章- 1  评论- 6 

1.不可做题。

求出满足
$$\sum_{i=1}^{m}{x_i}\leq s$$
对任意$$i\leq m,x_i>0$$
对所有$$i,x_i\leq 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

 

 posted on 2020-03-10 16:47  GreenDuck  阅读(...)  评论(...编辑  收藏