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;
}