jz集训 8.20

50

T1 旅游

Description

ztxz16如愿成为码农之后,整天的生活除了写程序还是写程序,十分苦逼。终于有一天,他意识到自己的生活太过平淡,于是决定外出旅游丰富阅历。

ztxz16生活的城市有NM个景点,可以描述成一个NM的矩形,每个景点有一个座标(x, y) (1 <= x <= N, 1 <= y <= M)以及美观度A[x][y]和观赏所需的时间B[x][y],从一个景点(x1, y1)走到另一个景点(x2, y2)需要时间为它们之间的曼哈顿距离:|x1 - x2| +|y1 - y2|。

为了防止审美疲劳,ztxz16希望观赏的景点的的美观度是严格上升的,由于不想太早回家码代码,ztxz16希望旅游的总时间尽可能长。

Input

第一行输入两个整数N, M;

接下来N行每行M个整数,第x行第y个整数代表A[x][y];

接下来N行每行M个整数,第x行第y个整数代表B[x][y];

注意,有一些A[x][y]=B[x][y]=0,说明这个景点已经拆除,不能游览;

Output

输出一行代表最长的总时间。

Sample Input

4 5

1 2 6 0 2

1 3 4 0 4

0 0 4 0 3

2 2 0 0 4

1 3 5 0 2

2 8 1 0 2

0 0 3 0 4

0 5 0 0 3

Sample Output
39

【样例说明】

游览顺序为(2,1)->(1,5)->(2,2)->(4,5)->(1,3)

Data Constraint

对于30%的数据:1<=N<=50 , 1<=M<=50

对于60%的数据:1<=N<=300 , 1<=M<=300

对于100%的数据:1<=N<=1000 , 1<=M<=1000

0<=A[x][y]<=1000000

0<=B[x][y]<=10^9

注意:本题输入数据较大,请注意输入消耗的时间\

Solution

注意到最优情况肯定是从美观值小的一路选到大的。
首先对点关于美观值排序。
对于一个点,仅向第一个比它大的美观值的所有点连边。
这就是说,我们将点分成了很多层,分层的依据是美观值,每相邻的两层间连边。
跑一遍最长路即可。

这个算法显然是错的,但它能过。

因为这个算法连的边数与美观值的种类密切相关。
例如:当美观值仅有1和2,有一半的点是1,一半的点是2,那么连的边数就是n4n^4级别的。

T2 做梦

Description

ztxz16旅游归来后十分疲倦,很快就进入了梦中。

在梦中ztxz16结婚生子了,他不得不照顾小宝宝。但这实在太无聊了,于是ztxz16会在散步。梦中ztxz16住在一个类似数轴的街上,数轴上的每个整点是一个街区,每个单位时间内ztxz16可以选择向左走一个街区或者向右走一个街区,但如果他离开家超过m个单位时间小宝宝会有危险,因此ztxz16必须在距离上次在家中不超过m个单位时间内回到家中。

n个单位时间后ztxz16会醒来,他希望此时正好在家中。

ztxz16想知道散步过程可能有多少种不同的散步过程。两个散步过程被认为不同,当且仅当存在至少一个单位时刻ztxz16选择的走向不同。

Input

第一行输入两个整数n, m。

Output

输出可能的散步过程数%1000000007。

Sample Input

输入1:

4 2

输入2:

10 6

Sample Output

输出1:

4

输出2:

184

Data Constraint

对于30%的数据:2<=n<=100, 2<=m<=100

对于100%的数据:2<=n<=10^9, 2<=m<=100

n和m均为偶数

Solution

咕咕咕

T3 数数

Description

ztxz16从小立志成为码农,因此一直对数的二进制表示很感兴趣。今天的数学课上,ztxz16学习了等差数列的相关知识。我们知道,一个等差数列可以用三个数A,B,N表示成如下形式:

B + A, B + 2 * A, B + 3 * A, …, B + N * A

ztxz16想知道对于一个给定的等差数列,把其中每一项用二进制表示后,一共有多少位是1,但他的智商太低无法算出此题,因此寻求你的帮助。

Input

第一行输入一个整数T代表数据组数;

接下来T行每行输入三个整数A,B,N;

Output

输出T行,每行一个整数代表答案。

Sample Input

2

4 7 1

5 8 2

Sample Output

3

5

Data Constraint

对于30%的数据:

1<=T<=20 , 1<=A<=10000 , 1<=B<=101610^{16}, 1<=N<=10310^3

对于60%的数据:

1<=T<=20 , 1<=A<=10000 , 1<=B<=101610^{16} , 1<=N<=10910^9

对于100%的数据:

1<=T<=20 , 1<=A<=10000 , 1<=B<=101610^{16} , 1<=N<=101210^{12}

Solution

类欧。
Q:类欧是什么?
A:解决类似 fa,b,c,n=i=0nai+bcf_{a,b,c,n}=\sum\limits_{i=0}^{n} \lfloor\frac{ai+b}{c}\rfloor的问题的算法,复杂度lognlog_n

Q:怎么将复杂度降到lognlog_n
A:我们注意到,当aca\geq cbcb\geq c时,令a=amod&ThinSpace;&ThinSpace;ca&#x27;=a \mod cb=bmod&ThinSpace;&ThinSpace;cb&#x27;=b\mod c,有:
fa,b,c,n=i=0nai+bc+n×(n+1)2ac+(n+1)bcf_{a,b,c,n}=\sum\limits_{i=0}^{n} \lfloor\frac{a&#x27;i+b&#x27;}{c}\rfloor+\frac{n\times (n+1)}{2}\lfloor \frac{a}{c} \rfloor +(n+1) \lfloor \frac{b}{c} \rfloor
如果不满足,令m=an+bcm=\lfloor \frac{an+b}{c} \rfloor则有
fa,b,c,n=nm+fc,cb1,a,m1f_{a,b,c,n}=nm+f_{c,c-b-1,a,m-1}
证明如下:
fa,b,c,n=i=0nai+bcf_{a,b,c,n}=\sum\limits_{i=0}^{n} \lfloor\frac{ai+b}{c}\rfloor
fa,b,c,n=i=0nj=1m(jai+bc)f_{a,b,c,n}=\sum_{i=0}^{n} \sum_{j=1}^m(j\leq \lfloor\frac{ai+b}{c}\rfloor)
fa,b,c,n=i=0nj=0m1(j+1ai+bc)f_{a,b,c,n}=\sum_{i=0}^{n} \sum_{j=0}^{m-1}(j+1\leq \lfloor\frac{ai+b}{c}\rfloor)
fa,b,c,n=i=0nj=0m1(jc+cbai)f_{a,b,c,n}=\sum_{i=0}^{n} \sum_{j=0}^{m-1}(jc+c-b\leq ai)
fa,b,c,n=i=0nj=0m1(jc+cb1&lt;ai)f_{a,b,c,n}=\sum_{i=0}^{n} \sum_{j=0}^{m-1}(jc+c-b-1&lt; ai)
fa,b,c,n=i=0nj=0m1(jc+cb1a&lt;i)f_{a,b,c,n}=\sum_{i=0}^{n} \sum_{j=0}^{m-1}(\lfloor \frac{jc+c-b-1}{a}\rfloor&lt; i)
fa,b,c,n=j=0m1(njc+cb1a)f_{a,b,c,n}=\sum_{j=0}^{m-1}(n-\lfloor \frac{jc+c-b-1}{a}\rfloor)
fa,b,c,n=nm+j=0m1jc+cb1af_{a,b,c,n}=nm+\sum_{j=0}^{m-1}\lfloor \frac{jc+c-b-1}{a}\rfloor
fa,b,c,n=nm+fc,cb1,a,m1f_{a,b,c,n}=nm+f_{c,c-b-1,a,m-1}
得证。

当我在学这个算法的时候,我看到别人的证明过程也十分懵逼,其实理解这个式子要加入一点数形结合的思想。
原式表达的是什么?
在这里插入图片描述
在满足xNx\in N,yNy\in N,x[0,n]x\in[0, n]y(0,ax+bc]y\in(0,\frac{ax+b}{c}]的二元组(x,y)(x, y)的个数。
第一步转换就是从x=0x=0枚举到x=mx=m,发现点就加1。
如下图:
在这里插入图片描述

jj11一直扫到mm

剩下的就是代数变换过程了,不多赘述。

回到本题。
在这里插入图片描述

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
typedef unsigned long long ull;
const int L = 65;
ull t,a,b,n,ans;
ull k[L];
ull f(ull a,ull b,ull c,ull n){
	ull res=(n+1)*(b/c);
	if(n & 1){
		res+=(n+1)/2*n*(a/c);
	}
	else{
		res+=n/2*(n+1)*(a/c);
	}
	a%=c;
	b%=c;
	ull m=(a*n+b)/c;
	if(m==0){
		return res;
	}
	return res+n*m-f(c, c-b-1, a, m-1);
}
int main(){
	scanf("%llu",&t);
	k[0]=1;
	for(int i=1; i<62; i++){
		k[i]=k[i-1]*2;
	}
	while(t--){
		scanf("%llu%llu%llu",&a,&b,&n);
		ans=0;
		for(int i=0; i<=60; i++){
			if(b & k[i]){
				ans--;
			}
		}
		for(int i=0; i<=60; i++){
			ans+=f(a, b, k[i], n)-f(a, b, k[i+1], n)*2;
		}
		printf("%llu\n",ans);
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章