1002模拟赛订正(待更)

写在前面

这次的模拟赛,又爆炸了……(为什么自己每次都会有很多的失误,有点难过。)

这次出现的问题:

  1. 第一题中,注意在做除法的时候前面的被除数是不可以进行取模的操作,因为除法的取模是不满足同模原理的,要注意什么时候做除法
  2. 第一题中,注意如果是两个longlong在取模之后也可能是会爆掉longlong的,所以我们要用大整数乘法
  3. 第二题中,我的sort 死掉了。注意sort是左闭右开的操作,所以,当你要排序[l,r]中间的数字的时候,sort中应该是sort(a+l,a+r+1);;
  4. 在第三题的时候,思路错误。自己想的是求出次短路,但是实际上,——<>——最短路和次短路之间是可能有相同的边的,那么当我删掉这条共同的边的同时,最短路和次短路就都是不合法的答案。

调整自己的状态,加油!


正文

第三题好毒瘤,至今不会……

第一题

求和
【问题描述】
一个无限大的二维矩阵d,满足 d i , j = i + j − 1 d_i,j=i+j-1 di,j=i+j1。再给定 x 1 , y 1 , x 2 , y 2 x_1,y_1,x_2,y_2 x1,y1,x2,y2,你需要求出矩阵d在以 x 1 , y 1 x_1,y_1 x1,y1为左上角、 x 2 , y 2 x_2,y_2 x2,y2为右下角的矩形内的元素和,即需要求出 ∑ i = x 1 x 2 ∑ i = y 1 y 2 d i , j \sum^{x2}_{i=x1}\sum^{y2}_{i=y1}d_i,j i=x1x2i=y1y2di,j的值。为了避免大规模的输出,你只需要输出答案对一个给定的大整数m取模后的结果。
【输入文件】
一行五个正整数 x 1 , y 1 , x 2 , y 2 , m x_1,y_1,x_2,y_2,m x1,y1,x2,y2,m
【输出文件】
输出一个整数,为所求的答案对m取模后的结果。
【输入输出样例】
square.in
2 1 5 3 10007
square.out
54
【数据规模和约定】
对于20%的数据,满足 x 2 , y 2 , m ≤ 1000 x_2,y_2,m≤1000 x2,y2,m1000
对于40%的数据,满足 x 2 , y 2 , m ≤ 100000 x_2,y_2,m≤100000 x2,y2,m100000
对于70%的数据,满足 x 2 , y 2 , m ≤ 1 0 9 x_2,y_2,m≤10^9 x2,y2,m109
对于100%的数据,满足 1 ≤ x 2 , y 2 , m ≤ 1 0 18 , 1 ≤ x 1 ≤ x 2 , 1 ≤ y 1 ≤ y 2 1≤x_2,y_2,m≤10^{18},1≤x_1≤x_2,1≤y_1≤y_2 1x2,y2,m10181x1x21y1y2

题解

【简要题解】
首先,我们可以把问题转化为求一个左上角为1,1,左下角为n,m的子矩形的和,通过差分即可完成这一步操作。
容易推出,上面的问题的答案为 ( n × m × ( n + m ) ) 2 \frac{(n×m×(n+m))}{2} 2(n×m×(n+m))。将公式代入即可得到70%的分数。

如下图:
n行 { 1 2 3 ⋯ 1 + n − 1 2 3 4 ⋯ 2 + n − 1 ⋮ ⋮ n n + 1 n + 2 ⋯ m + n − 1 ⏟ m项 \text{n行}\begin{matrix}\underbrace{ \left\{ \begin{matrix}1&2&3&\cdots&1+n-1\\2&3&4&\cdots&2+n-1\\\vdots&&&&\vdots\\n&n+1&n+2&\cdots&m+n-1\end{matrix}\right. }\\\text{m项}\end{matrix} n 12n23n+134n+21+n12+n1m+n1m

我们可以发现,对于相对的数字加起来的值是定值(m+n),一共有 m ∗ n 2 \frac{m*n}{2} 2mn个数字,所以最后的答案就是 ( n × m × ( n + m ) ) 2 \frac{(n×m×(n+m))}{2} 2(n×m×(n+m))

对于最后30%,乘法操作会超出2^64,不能直接相乘取模。我们可以使用高精度来解决这个问题,也可以把乘法操作看作很多次加法操作,利用快速幂的思想予以解决(大整数乘法)。


第二题

分组配对
【问题描述】
在一个班级中,恰好有n名男生和n名女生。为了便于管理,老师给这n名男生和n名女生分别从1到n进行编号。
某一天,老师在班级里开展了一项游戏。这个游戏需要将班级里的同学分成若干个不同的小组,且每个小组中需要同等数量的男生和女生。每个小组中,每一名男生需要和一名同小组的女生进行配对搭档,来完成游戏中的任务。一名男生不能和多名女生进行配对,一名女生也不能和多名男生进行配对。
老师决定采用一种比较简便的方式对全班同学进行分组:按编号顺序进行划分。具体来说,老师会确定若干个区间 [ l 1 , r 1 ] , [ l 2 , r 2 ] , … , [ l k , r k ] [l_1,r_1 ],[l_2,r_2 ],…,[l_k,r_k ] [l1,r1],[l2,r2],,[lk,rk],满足 l 1 = 1 , r k = n , l i = r ( i − 1 ) + 1 ( 1 < i ≤ k ) l_1=1,r_k=n,l_i=r_(i-1)+1(1<i≤k) l1=1rk=nli=r(i1)+1(1<ik),编号处于同一个区间的男生和女生分为一组。
为了让游戏保证尽量公平,老师希望没有哪一个小组的实力过于突出。具体来说,每名同学都有一个正整数实力值,用来衡量一名同学的能力大小。当一名实力值为a和一名实力值b的女生进行配对时,这一对同学的实力值就会是a×b。而一个小组的综合实力就是这个小组中每一对同学的实力值的和。为了保证不出现综合实力过高的小组,老师希望在分组后,不论小组内如何配对,每个小组的综合实力都不会超过一个给定值M。
最后,为了缩短游戏进行的时间,老师希望所分的小组数量尽可能少。你需要帮助他求出:在满足上述分组规则的情况下,最少的小组数量是多少?
【输入文件】
输入文件第一行为两个正整数n,M。
接下来两行,第一行为n个正整数 a 1   a n a_1~a_n a1 an,其中 a i a_i ai表示编号为i的男生的实力值;第二行为n个正整数 b 1   b n b_1~b_n b1 bn,其中 b i b_i bi表示编号为i的女生的实力值。
【输出文件】
输出一个整数,为最少的小组数量。输入数据保证至少存在一种满足分组规则的分组方式。
【输入输出样例】
pair.in
3 50
6 7 2
6 3 5
pair.out
2
【数据规模和约定】
对于10%的数据,满足n≤10。
对于30%的数据,满足n≤1000。
对于50%的数据,满足n≤10000。
对于70%的数据,满足n≤100000。
对于100%的数据,满足 1 ≤ n ≤ 500000 , 1 ≤ a i , b i ≤ 100000 , 1 ≤ M ≤ 1 0 15 1≤n≤500000,1≤a_i,b_i≤100000, 1≤M≤10^{15} 1n5000001ai,bi100000,1M1015

题解

首先,容易发现一个小组内的最优配对方式(能得到最大综合实力的方式)为:实力值最大的男生和最大的女生配对,次大的和次大的配对,以此类推。

接着,容易发现:在小组内增加一男一女,小组的最大综合实力值一定上升。以此我们容易得到一种贪心的分组方式:从编号1的人开始向后考虑,尽可能把人放进同一组,直到放下一对男生女生后最大综合实力值会超过M。用如此方法确定第一组,然后类似地确定第二组、第三组,直到分到最后一组。

一个比较麻烦的问题是,在小组内增加一男一女后,最大综合实力值并不方便快速统计。这意味着增量法不能使用。因此,我们可以用倍增+二分的方式来处理这个问题。对于每一组,考虑这组大小为 1 , 2 , 4 , … , 2 p 1,2,4,…,2^p 1,2,4,,2p时,最大综合实力值都没有超过M,但组大小为 2 ( p + 1 ) 2^{(p+1)} 2(p+1)时最大综合实力值会超过M,那么这组的最大大小应该在 2 p   2 ( p + 1 ) − 1 2^p~2^{(p+1)-1} 2p 2(p+1)1内。在此范围内进行二分即可。这样,当实际组大小是k时,时间复杂度应为 O ( k l o g 2 k ) O(klog^2 k) O(klog2k)。则总时间复杂度不超过 O ( n l o g 2 n ) O(nlog^2 n) O(nlog2n)

补充:由于这道题中的二分会被卡,(如果我构造一组数据是每一个都是长度为1的区间,那么,此时的二分还不如枚举……),所以,我们可以考虑倍增加速


第三题

不会……

城市游戏
【问题描述】
小A和小B正在进行一个游戏。这个游戏开展于一个城市中。城市中总共包含n个路口,从1到n进行编号。某些路口之间连接着具有一定长度的双向道路,道路总共有m条。
小A正在这个城市的1号路口,想要移动到n号路口。小B的目标是尽可能阻止小A。他的阻止方法是:在小A位于某个路口上时,永久地封闭城市中的一条道路。
如果小B使用封闭道路的权力只有一次,你需要求出:在此基础上,如果小A和小B都使用最佳策略(即小A希望他走到n号路口的总距离尽量小,小B希望小A的移动总距离尽量大),小A走到n号路口所需要移动的总距离是多少?
【输入文件】
第一行,两个整数n,m。
接下来m行,每行三个整数u,v,l,描述了一条道路连接的两个路口的编号以及道路的长度。
【输出文件】
输出一行一个整数,为所求的答案。若小A不能到n达号点,输出-1。
【输入输出样例】
city.in
4 4
1 2 1
2 3 1
3 4 1
1 4 1
city.out
3
【数据规模和约定】
对于20%的数据,满足n≤200,m≤1000
对于40%的数据,满足n≤1000,m≤2000
对于70%的数据,满足n≤3000,m≤10000
对于100%的数据,满足1≤n≤100000,1≤m≤200000,道路长度为不超过10^9的正整数。

有一个错误的算法:求出次短路。


code

第一题

这一个代码,并不是用的上面的结论,而是自己在考场上推出来的,在规定的矩阵中,可以把每一行的数字用等差数列累加,之后再求出每一行的累加。
等差数列求和的公式: S = a 1 ∗ n + n ∗ ( n − 1 ) 2 S=a1*n+\frac{n*(n-1)}{2} S=a1n+2n(n1)
注意:对于除以2而言,我们要特殊处理。

#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long ll;

ll x1, x2, s1, s2, MOD;
ll sum1, sum2, sum;

ll mul(ll a,ll b)
{
	ll ans=0;
	while(b)
	{
		if(b&1)	ans=(ans+a)%MOD;
		a=(a+a)%MOD;
		b>>=1;
	}
	return ans%MOD;
}

int main()
{
	freopen("sum.in","r",stdin);
	freopen("sum.out","w",stdout);
	scanf("%lld%lld%lld%lld%lld",&x1,&s1,&x2,&s2,&MOD);
	ll dx=x2-x1+1, dy=s2-s1+1;/*求出行数和列数,因为后面有/2,所以不可以在这里取模*/
	if(dy%2==0)	sum1=mul(dx, mul(dy/2, dy-1))%MOD;
	else	sum1=mul(dx, mul(dy, (dy-1)/2))%MOD;
	sum=(mul(x1+s1-1, dx))%MOD;/*a1*n*/ 
	if(dx%2==0)	sum2=(mul(dy, sum%MOD+mul(dx/2, dx-1)))%MOD;
	else	sum2=(mul(dy, sum%MOD+mul(dx, (dx-1)/2)))%MOD;
	sum=(sum1%MOD+sum2%MOD)%MOD;
	printf("%lld\n",sum%MOD);
	return 0;
} 

第二题

#include<bits/stdc++.h>
using namespace std;

const int nn=500003;
typedef long long ll;

int n, a[nn], b[nn], cnt=0;
int c[nn], d[nn];
ll M;

inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
	return x*f;
}

inline bool cmp(int a,int b) {return a>b;}

inline bool check(int l,int r)
{
	ll sum=0;
	for(int i=l;i<=r;++i)	c[i]=a[i], d[i]=b[i];
	sort(c+l,c+r+1,cmp), sort(d+l,d+r+1,cmp);/*注意是左闭右开的区间*/
	for(int i=l;i<=r;++i)
	{
		sum+=(ll)c[i]*d[i];
		if(sum>M) return false;
	}
	return true;
}

int main()
{
	freopen("pair.in","r",stdin);
	freopen("pair.out","w",stdout);
	scanf("%d%lld",&n,&M);
	for(int i=1;i<=n;++i)	a[i]=read();
	for(int i=1;i<=n;++i)	b[i]=read();
	int L=1, R=0;
	while(R<n)
	{
		int p=1;
		for(;L+p<n;p*=2)/*倍增的是区间的长度*/
			if(!check(L,L+p))	break;/*此时出来的p是不合法的*/
		int l=L+p/2, r=L+p, mid;
		while(l<r)
		{
			mid=(l+r+1)>>1;
			if(check(L,mid))	l=mid;
			else r=mid-1;
		}
		R=l, cnt++; 
		L=R+1;
	}
	cout<<cnt<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值