假设一个环形地图,上面有numCities个城市,一个企鹅在城市间移动,第k天可以往左或往右移动k步。给定daysPassed天时间,问在daysPassed天后回到起点的方法有多少? Problem Statement
可以用动态规划,记录每一次移动后在每一个位置的方法数。但这里因为daysPassed的取值可以到10^18,所以不能直接枚举每一天。因为每一天的实际移动是(k%numCities),所以其实移动的模式在经过numCities天后会重复出现,利用这点可以采用二分。
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include "string.h"
using namespace std;
class PenguinEmperor {
public:
int countJourneys(int, long long);
};
const long long M = 1000000007;
vector<long long> Mul(vector<long long> a, vector<long long> b){
int n=a.size();
vector<long long> c(n,0);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int next=(i+j)%n;
c[next]+=a[i]*b[j];
c[next]%=M;
}
}
return c;
}
vector<long long> Pow(vector<long long> a, long long n){
if(n==0){
a=vector<long long>(a.size(),0);
a[0]=1;
return a;
}
if(n%2==0)
return Pow(Mul(a,a),n/2);
else
return Mul(a,Pow(a,n-1));
}
int PenguinEmperor::countJourneys(int numCities, long long daysPassed) {
vector<long long> period(numCities,0),extra(numCities,0);
period[0]=extra[0]=1;
for(int i=1;i<numCities;i++){
vector<long long> move(numCities,0);
move[i]=move[numCities-i]=1;
period=Mul(period,move);
if(i<=(daysPassed%numCities))
extra=Mul(extra,move);
}
vector<long long> res=Mul(extra,Pow(period,daysPassed/(long long)numCities));
return (int)(res[0]%M);
}
<%:testing-code%>
//Author@logicnut
//Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!