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,那么连的边数就是级别的。
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<=, 1<=N<=
对于60%的数据:
1<=T<=20 , 1<=A<=10000 , 1<=B<= , 1<=N<=
对于100%的数据:
1<=T<=20 , 1<=A<=10000 , 1<=B<= , 1<=N<=
Solution
类欧。
Q:类欧是什么?
A:解决类似 的问题的算法,复杂度
Q:怎么将复杂度降到?
A:我们注意到,当或时,令,,有:
如果不满足,令则有
证明如下:
得证。
当我在学这个算法的时候,我看到别人的证明过程也十分懵逼,其实理解这个式子要加入一点数形结合的思想。
原式表达的是什么?
在满足,,和的二元组的个数。
第一步转换就是从枚举到,发现点就加1。
如下图:
从一直扫到。
剩下的就是代数变换过程了,不多赘述。
回到本题。
#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;
}