18.10.17队测
T1 :
题意简化 : 给出\(n\)个区间和\(m\)个点,问一个区间和一个点匹配,最多可以匹配多少个点。 其中,\(n\leq 2e5,m\leq2e5,a[i]\leq1e9\).
贪心,给点排序,然后把区间以右端点为关键字用一个set维护,每次对于一个点取右端点大于且最靠近这个点的区间。
#include<bits/stdc++.h>
using namespace std;
#define read(x) scanf("%d",&x)
#define write(x) printf("%d\n",x)
#define maxn 200005
#define inf 1e9
int n,m,a[maxn],ans;
struct data{int x,y;}c[maxn];
multiset<int > s;
multiset<int> :: iterator x;
bool cmp(data a,data b){return (a.y==b.y&&a.x<b.x)||a.y<b.y;}
int main(){
read(n),read(m);
for(int i=1;i<=m;i++) read(c[i].x),read(c[i].y);
for(int i=1;i<=n;i++) read(a[i]),s.insert(a[i]);
sort(c+1,c+m+1,cmp);s.insert(inf);
for(int i=1;i<=m;i++){
x=s.lower_bound(c[i].x);
if((*x)<=c[i].y&&x!=s.end()) ans++,s.erase(x);
}
write(ans);
return 0;
}
T2 :
题意简化: 问随机的树在模\(p\)的期望深度。构造方法:每次将第\(i\)个点在\([1,i-1]\)中随机的选一个点作为父亲。
其中:\(n\leq 200,p\leq1e9+7\),且\(p\)为质数。
对于\(50\%\)的数据,\(n\leq20\),可以状压dp,设\(f[sta]\)为状态为\(sta\)的方案数。
对于状态的记录,首先可以想到:第\(i\)位为\(h\)表示第\(i\)个点的高度是\(h\),但是这样不方便我们记录,所以将这个数列排序后差分一下,可以得到一个\(01\)串,然后状态转移可以类似的由\(1001001\)转移到\(10001001\)或\(10010001\)等。
对于所有数据,显然不能用上面的指数级dp。记\(dp[i][j]\)表示\(i\)个结点的森林深度为\(j\)的概率。
其中,由于一个点也是一棵树,可以单独存在,所以要除以\(i\)而不是\(i-1\)。
然后记\(f[i][j]\)表示i个点的树深度小于等于j的概率,\(g[i][j]\)为i个点的森林深度小于等于j的概率。
首先,显然\(f[i ][ j ]=g[i-1][j-1]\) ,因为可以设一个根节点连向森林里的所有树,然后深度\(+1\).然后,
这个也比较显然,然后最后对于深度为i的概率可以由\(f[n][i]-f[n][i-1]\)得到。
初值以及小细节什么的看代码吧。。说实话这个dp是真的难想到。。
#pragma GCC optimize(3)
#include<cstdio>
#define int long long
#define max(a,b) (a<b?b:a)
#define min(a,b) (a<b?a:b)
#define swap(x,y) x^=y^=x^=y
#define isdigit(ch) (ch>='0'&&ch<='9')
#define abs(x) (x<0?-x:x)
#define base 2333
#define pb push_back
inline void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);x*=f;
}
inline void print(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline void write(int x) {print(x);puts("");}
#define maxn 230
int dp[maxn][maxn],g[maxn][maxn],f[maxn][maxn],n,p,inv[maxn];
signed main() {
read(n),read(p);inv[1]=1;inv[0]=1;
for(int i=2;i<=n;i++) inv[i]=(p-p/i)*inv[p%i]%p;
dp[1][1]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<=n;j++)
dp[i][j]=(dp[i-1][j-1]*(j-1)%p*inv[i]%p+dp[i-1][j]*(i-j)%p*inv[i]%p)%p;
for(int i=0;i<=n;i++) f[1][i]=g[1][i]=f[0][i]=g[0][i]=1;g[1][0]=0;
for(int i=2;i<=n;i++)
for(int j=1;j<=n;j++) {
f[i][j]=g[i-1][j-1];
for(int k=1;k<=i;k++) (g[i][j]+=f[k][j]*g[i-k][j]%p*dp[i][k])%=p;
}
int ans=0;
for(int i=1;i<=n;i++) ans=(ans+i*(f[n][i]-f[n][i-1]))%p;
write((ans-1+p)%p);
return 0;
}
T3 :
题意简述 :
给出一颗有编号的树,每次选择一个区间的编号,问有多少个联通块。
其中\(n\leq 2e5,q\leq2e5\).
\(n\leq2000\)暴力有50分。。
其实这题和树一点关系也没有。。。
可以发现,对于一个区间\([l,r]\),先令\(ans=r-l+1\),当且仅当一条边\(<u,v>(u<v)\) 满足\(l\leq u,v\leq r\)时,才可以令\(ans--\).
于是这就变成了一个基本的二维偏序问题。。用个树状数组或者什么的维护下就好了。
#pragma GCC optimize(3)
#include<cstdio>
#include<algorithm>
using std :: sort;
#define max(a,b) (a<b?b:a)
#define min(a,b) (a<b?a:b)
#define swap(x,y) x^=y^=x^=y
#define isdigit(ch) (ch>='0'&&ch<='9')
#define abs(x) (x<0?-x:x)
#define pb push_back
const int mod = 1e9+7;
inline void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);x*=f;
}
inline void print(int x) {
if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
}
inline void write(int x) {print(x);puts("");}
#define maxn 2000050
int n,q;
struct node {int l,r,x,ans,id;}a[maxn];
struct binary_index_tree {
int tree[maxn];
void modify(int x,int v) {for(int i=x;i<=n;i+=i&-i) tree[i]+=v;}
int query(int x,int ans=0) {for(int i=x;i;i-=i&-i) ans+=tree[i];return ans;}
}T;
int cmp_l(node aa,node b) {return aa.l<b.l||(aa.l==b.l&&aa.r>b.r)||(aa.l==b.l&&aa.r==b.r&&aa.x>b.x);}
int cmp_id(node aa,node b) {return aa.id<b.id;}
int main() {
read(n),read(q);
for(int i=1;i<n;i++) {read(a[i].l),read(a[i].r),a[i].x=1;if(a[i].l>a[i].r) swap(a[i].r,a[i].l);}
for(int i=n;i<=n+q-1;i++) read(a[i].l),read(a[i].r),a[i].x=2,a[i].ans=a[i].r-a[i].l+1,a[i].id=i;
sort(a+1,a+n+q,cmp_l);
for(int i=n+q-1;i;i--) {
if(a[i].x==1) T.modify(a[i].r,1);
else a[i].ans-=T.query(a[i].r);
}
sort(a+1,a+n+q,cmp_id);
for(int i=n;i<n+q;i++) write(a[i].ans);
return 0;
}