DTOI 10.24 测试(被爆屠) orz IcePrincess_1968

T1. 梦境
(dream.cpp/c/pas)
【问题描述】
智者奥尔曼曾说过:有缘的人即使相隔海角天涯,也会在梦境中相遇。
IcePrince_1968 和IcePrincess_1968 便是如此。有一天IcePrincess_1968 突发奇想:为什
么不用梦境操控仪器来增加她和IcePrince_1968 的缘分呢?
IcePrincess_1968 的梦境可以用n 个区间来表示,第i 个区间[li,ri]表示她的第i 个梦境会
在li 时刻开始,在ri 时刻结束(包含li 和ri 两个时刻)。因为IcePrincess_1968 经常做白日
梦,所以n 可能很大。
两个人的梦境不是什么时候都能融合的。只有在一些关键的与另一个人相关的梦境转折
点两个人的梦境相遇, 才能完成融合, 形成浪漫的梦境。IcePrincess_1968 探测到
IcePrince_1968 近期的m 个与IcePrincess_1968 相关的梦境转折点,第i 个转折点ti 表示他
的第i 个梦境转折点会在ti 时刻出现。因为IcePrince_1968 和IcePrincess_1968 很有缘,
IcePrince_1968 经常梦到IcePrincess_1968,所以m 可能会很大。
当IcePrincess_1968 的一个梦境包含了IcePrince_1968 的一个梦境转折点时,两个人的
这两段梦境就能得到融合。但要注意IcePrincess_1968 的每段梦境只能和IcePrince_1968 的
一个梦境转折点融合,类似的,IcePrince_1968 的每个梦境转折点只能和IcePrincess_1968
的一段梦境融合,否则会引发时空混乱。
IcePrincess_1968 很喜欢做和IcePrince_1968 相关的梦。所以她想算出她的这些梦境最
多能和IcePrince_1968 的梦境转折点融合出多少个浪漫的梦境。IcePrincess_1968 擅长文学
但不擅长计算机,所以只能找你帮忙。
【输入格式】
输入文件名为dream.in。
文件的第一行为有两个正整数n,m,表示IcePrincess_1968 的梦境个数和IcePrince_1968
的与IcePrincess_1968 相关的梦境转折点个数。
第2 至第n+1 行,每行两个正整数li,ri,第i+1 行的两个数刻画了IcePrincess_1968 的
第i 段梦境,含义如题面中所述。
第n+2 至第n+m+1 行,每行一个正数ti,第i 行的两个数刻画了IcePrince_1968 的第i-n-1
个梦境转折点,含义如题面中所述。
【输出格式】
输出文件名和dream.out。
输出文件仅一行,一个非负整数N 表示IcePrincess_1968 最多能获得多少段浪漫的梦境。

题解:

考场上,看到这题,我先想到的是不是什么贪心,而是线段树优化网络流建边。。。。

本来想直接开打的,后面想想,noip模拟真的会出这种东西吗?(他一定是很良心的)

但是其实远没有那么麻烦,考虑贪心。

我们将所有梦境区间按照左端点排序,将转折点也按照从小到大排序。

对于某一个转折点,我们需要找到左端点小于它的区间中,找到右端点比他大的最小的区间,则他一定是最优的。

我们从左到右扫过转折点,然后用一个堆来维护这些合法的区间,用一个指针扫扫就可以了。

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define re register
#define rep(i,a,b) for(re int i=a;i<=b;i++)
#define repd(i,a,b) for(re int i=a;i>=b;i++)
#define For(i,a,b) for(int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=2e5+4;
int n,m;
struct A{int l,r;bool operator<(A t)const{return r>t.r;}}a[N];
int t[N],ans; priority_queue<A> q;
bool cmp1(A t1,A t2){return t1.l<t2.l||(t1.l==t2.l&&t1.r<t2.r);}
int main(){
    freopen("dream.in","r",stdin);freopen("dream.out","w",stdout);
    g(n),g(m);
    rep(i,1,n) g(a[i].l),g(a[i].r);
    rep(i,1,m) g(t[i]);
    sort(a+1,a+1+n,cmp1);sort(t+1,t+1+m);
    int j=1;
    rep(i,1,m){
        while(j<=n&&a[j].l<=t[i]){q.push(a[j]);j++;}
        while(!q.empty()&&q.top().r<t[i]) q.pop();
        if(!q.empty()) ans++,q.pop();
    }
    return !printf("%d",ans);
}

T2. 玩具
(toy.cpp/c/pas)
【问题描述】
这个故事发生在很久以前,在IcePrincess_1968 和IcePrince_1968 都还在上幼儿园的时候。
IcePrince_1968 最近迷上了一种玩具,这种玩具中有两种零件:圆球和棍子。棍子的两头可
以插在两个圆球上的各一个空洞中,从而将两个圆球连接起来。为了保证玩具的娱乐性,任意一
个圆球上的空洞个数总是多于玩具套装中的棍子数。你可以认为圆球是没有体积的,所有棍子
的长度均为1。
IcePrince_1968 喜欢这样玩这种玩具:他先摸出玩具袋里的一个圆球放在地上,然后重复下
面的操作n-1 次:每次从袋中取出一个圆球和一根棍子,然后等概率的从地上的圆球中选择一个,
将该圆球和选择的圆球用棍子连起来,使得新的圆球在选中圆球的正上方。
IcePrince_1968 对自己搭出的艺术品很满意,便决定把这个物品送给IcePrincess_1968 作为
生日礼物。然而生日礼物是需要包装的,因为默认圆球没有体积,所以IcePrince_1968 不用考虑
包装盒的长和宽,但是包装盒的高是需要确定的,这里我们假设IcePrince_1968 是一个非常节俭
的孩子,所以包装盒的高总是等于艺术品的高度。IcePrince_1968 想知道自己需要的包装盒的高
的期望对质数p 取模后的值,但他还在上幼儿园,怎么会算呢,于是就请你来帮助他。
【输入格式】
输入文件名为toy.in。
输入数据仅一行,包含两个正整数n,p,表示最终的艺术品中圆球的个数和模数p。
【输出格式】
输出文件名为toy.out。
输入文件仅一行,一个正整数,表示包装盒的高的期望对质数p 取模后的值。
【输入输出样例1】
toy.in                                   toy.out
3  998244353                   499122178
【输入输出样例1 解释】
三个圆球组成的艺术品,高度只可能是1 或者2,所以高度的期望是1.5,在模998244353
下的期望是499122178。
【输入输出样例2】
见选手目录下的toy/toy2.in 和toy/toy2.ans。
【数据规模与约定】
对于30%的数据,满足n<=10,p<=1,000,007;
对于50%的数据,满足n<=20;
对于70%的数据,满足n<=50;
对于100%的数据,满足n<=200,p<=1,000,000,007,p 是质数。

 题解:

神题(orzJyc 省队爷&&北大爷考场拿到最高分)

现在来讲正解:

f_{i,j}表示有 i个点,深度不超过j层的概率,g_{i,j}i个点的森林,深度不超过j的概率。

然后还需要一个预处理:

dp_{i,j}表示对于有i个点的森林,有j个点在第一个子树内的概率。

则可以表示为:

dp_{i,j}=dp_{i-1,j-1}\times (j-1)\times inv(i) + dp_{i-1,j}\times (i-j)\times inv(i)

然后又因为f_{i,j}可以从g_{i-1,j-1}直接转移过来,so:

g_{i,j}= \sum_{k=1}^{i} f_{k,j} \times g_{i-k,j} \times dp_{i,k}

答案即\sum_{i=1}^{n-1} (f_{n,i}-f_{n-1,i})

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define re register
#define rep(i,a,b) for(re int i=a;i<=b;i++)
#define repd(i,a,b) for(re int i=a;i>=b;i--)
#define For(i,a,b) for(int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=304;
typedef long long ll;ll mod,n;
ll inv[N],f[N][N],h[N][N],dp[N][N];
int main(){
	//freopen(".in","r",stdin);freopen(".out","w",stdout);
	g(n),g(mod);inv[0]=inv[1]=1;dp[1][1]=1;
	rep(i,2,n) inv[i]=(mod-mod/i)*inv[mod%i]%mod,(inv[i]+=mod)%=mod;
	rep(i,2,n) rep(j,1,i){
		dp[i][j]=dp[i-1][j-1]*(j-1)%mod*inv[i]%mod+dp[i-1][j]*(i-j)%mod*inv[i]%mod;
		dp[i][j]%=mod;
	}
	rep(i,0,n) h[0][i]=1;
	rep(i,1,n){
		rep(j,0,n){
			if(j) f[i][j]=h[i-1][j-1];
			else f[i][j]=(i<2);
			rep(k,1,i){
				h[i][j]=(h[i][j]+f[k][j]*h[i-k][j]%mod*dp[i][k]%mod)%mod;
			}
		}
	}
	ll ans=0;
	For(i,1,n){
		ans+=(f[n][i]%mod-f[n][i-1]%mod)*i%mod;
		ans%=mod;
	}
	return !printf("%lld",(ans+mod)%mod);
}

T3. 飘雪圣域
(icekingdom.cpp/c/pas)
【问题描述】
IcePrincess_1968 和IcePrince_1968 长大了,他们开始协助国王IceKing_1968 管理国内
事物。
IcePrincess_1968 和IcePrince_1968 住在一个宁静悠远的王国:IceKingdom —— 飘雪圣
域。飘雪圣域有n 个城镇,编号1,2,3...n。有些城镇之间有道路,且满足任意两点之间有且
仅有一条路径。飘雪圣域风景优美,但气候并不是太好。根据IcePrince_1968 的气候探测仪,
将来会发生q 场暴风雪。每场暴风雪可以用两个整数li,ri 刻画,表示这场暴风雪之后,只有
编号属于[li,ri]的城市没有受到暴风雪的影响。
在暴风雪的影响下迅速确定王国的农业生产方案是非常重要的事情。IceKing_1968 认
为,一个农业生产地域应该是一个极大连通块,满足每个节点都没有被暴风雪影响。这里极
大连通块的定义是:不存在一个不属于该点集的未被暴风雪影响的点与该连通块连通。
IcePrincess_1968 要负责算出每次暴风雪后,王国能拥有多少个农业生产地域。注意这
里每次暴风雪是独立的,即每次暴风雪过后,直到每个城镇重新焕发生机,下一次暴风雪才
会到来。
正如上文所述,IcePrincess_1968 擅长文学但不擅长计算机,于是请你帮忙。
【输入格式】
输入文件名为icekingdom.in。
第一行包含两个正整数n,q,表示IceKingdom 的城镇个数和暴风雪次数。
第2 至第n 行,每行两个正整数x,y,表示城镇x 和城镇y 之间有一条道路。
第n+1 至第n+q 行,每行两个正整数li,ri,描述一场暴风雪,含义如题面所述。
【输出格式】
输出文件名icekingdom.out。
输出文件共有q 行,第i 行表示在第i 场暴风雪之后农业生产地域的个数。

【数据规模和约定】
对于30%的数据:n<=100,q<=100;
对于50%的数据:n<=2,000,q<=2,000;
对于100%的数据:n<=200,000,q<=200,000,对于所有的暴风雪,li<=ri。

 题解:

又是一道神题。

首先应改要发现,这是一棵树。直接从联通块的角度考虑好像不太可以,于是可以从边的角度来解决。

考虑对于每一个询问,,只要知道两个端点都没有被暴雪影响到的边的条数num,就能算出连通块的个数。考虑每新加条边,就会少一个联通块,答案即是 r_{i}-l_{i}+1-num.

然后考虑将询问离线,按照右端点从小到大排序。

用树状数组维护每个询问,将这个区间的左端点加入树状数组。

然后将边按照点编号较大的点的编号从小到大排序。

于是可以转化为,在询问区间有几条边存在。

于是就可以用树状数组。如果某条边右端点在询问区间内,将左端点插入树状数组,然后在询问一下就好了。

ps: 考场上还有一些神仙写出了主席树orzorzorz

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define re register
#define rep(i,a,b) for(re int i=a;i<=b;i++)
#define repd(i,a,b) for(re int i=a;i>=b;i--)
#define For(i,a,b) for(int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=2e5+4;
struct E{int l,r,id;}e[N],q[N];
int n,Q,t[N];
bool cmp(E a,E b){return a.r<b.r;}
in void ins(int x,int v){
    for(;x<=n;x+=x&-x) t[x]+=v;
}
in int que(int x){
    int res=0;
    for(;x;x-=x&-x) res+=t[x];
    return res; 
}
int ans[N];
int main(){
    //freopen(".in","r",stdin);freopen(".out","w",stdout);
    g(n),g(Q);
    For(i,1,n){
        g(e[i].l),g(e[i].r);
        if(e[i].l>e[i].r) swap(e[i].l,e[i].r); 
    }
    rep(i,1,Q){
        g(q[i].l),g(q[i].r),q[i].id=i;
        if(q[i].l>q[i].r) swap(q[i].l,q[i].r); 
    }
    sort(e+1,e+n,cmp);sort(q+1,q+1+Q,cmp);
    int j=1;
    rep(i,1,Q){
        while(q[i].r>=e[j].r&&j<n) ins(e[j].l,1),j++;
        int s=que(q[i].r)-que(q[i].l-1);
        ans[q[i].id]=q[i].r-q[i].l+1-s;
    }
    rep(i,1,Q) printf("%d\n",ans[i]);
    return 0;
}
 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可爱の小公举

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值