行列
線形漸化式で定義される数列の一般項を確定する。数列の最初のほうの項をaとしたとき
est.build(a)でaを与え、est.get(n)でn項目を取得する。
TODO:Codeforces 230 Div1C
ll mod=1000000007;
struct mint{
ll value;
mint():value(0){}
mint(ll v):value((v%mod+mod)%mod){}
};
mint& operator+=(mint&a, mint b){return a=a.value+b.value;}
mint& operator-=(mint&a, mint b){return a=a.value-b.value;}
mint& operator*=(mint&a, mint b){return a=a.value*b.value;}
mint operator+(mint a, mint b){return a+=b;}
mint operator-(mint a, mint b){return a-=b;}
mint operator*(mint a, mint b){return a*=b;}
mint operator-(mint a){return 0-a;}
bool operator==(mint a, mint b){return a.value==b.value;}
bool operator!=(mint a, mint b){return a.value!=b.value;}
std::ostream& operator<<(std::ostream& os, const mint& m){
return ( os << m.value );}
ll extgcd(ll a, ll b, ll &x, ll &y){
ll d=a;
if(b!=0){
d=extgcd(b, a%b, y, x);
y-=(a/b)*x;
}
else{
x=1,y=0;
}
return d;
}
ll modinverse(ll a, ll b){
ll x,y;
ll d=extgcd(a,b, x, y);
assert(d==1);
return (x%b+b)%b;
}
mint& operator/=(mint&a, mint b){return a=a.value*modinverse(b.value,mod);}
mint operator/(mint a, mint b){return a/=b;}
template <typename T> struct matrix : vector<vector<T > >{
matrix(int n){
vector<vector<T> >::clear();
resize(n, vector<T>(n) );
REP(i,n) (*this)[i][i]=1;
}
matrix(int n, int m){
vector<vector<T> >::clear();
resize(n, vector<T>(m) );
}
matrix<T> operator*(const matrix<T> &b){
int n1=this->size(), n2=b.size(), n3=b[0].size();
assert(this->size()==n2);
matrix<T> ret(n1,n3);
REP(i,n1) REP(j,n3) REP(k,n2) ret[i][j]=ret[i][j]+(*this)[i][k]*b[k][j];
return ret;
}
matrix<T> pow(ll n){
int m=this->size();
assert((*this)[0].size()==m);
return pow2(matrix<T>(m) ,n);
}
matrix<T> pow2(matrix t, ll n){
if(n==0)return t;
if(n%2==0)return ((*this)*(*this)).pow2( t, n/2);
else return ((*this)*(*this)).pow2 ((*this)*t, n/2);
}
/*T det(){
int n=this->size();
vector<vector<T> >x;
REP(i,n) x.pb((*this)[i]);
T h=1;
REP(i,n){
FOR(j,i,n){
if(x[j][i]!=0 && j!=i){
REP(k,n)swap(x[j][k], x[i][k]);
h*=-1;
break;
}
}
if(x[i][i]==0)return 0;
T v=1/x[i][i];
h=h*x[i][i];
FOR(j,i+1,n){
T v2=v*x[j][i];
REP(k,n) x[j][k]=x[j][k]-x[i][k]*v2;
}
}
return h;
}*/
};
struct EST{
EST(){};
vector<mint> q_init;
vector<mint> q;
void build(vector<mint> given){
q_init=given;
int n=given.size()/2;
for(int k=0; k<=n; k++){
vector<mint> a(given.begin(), given.begin()+2*k);
bool b=build_partial(a, q);
//deb(k);deb(b);debl;
}
//debug(q);
//debug(q.size());
}
bool build_partial(vector<mint> a, vector<mint> &ret){
assert(a.size()%2==0);
int n=a.size()/2;
vector<vector<mint> > m(n, vector<mint>(n+1));
REP(i,n) REP(j,n+1) m[i][j]=a[i+j];
REP(y,n){
FOR(x,y,n) if(m[x][y]!=0){
REP(y2,n+1) swap(m[y][y2], m[x][y2]);
break;
}
if(m[y][y]==0)return false;
{
mint z=m[y][y];
REP(y2,n+1) m[y][y2]/=z;
}
assert(m[y][y]==1);
REP(x,n){
if(x==y)continue;
mint z=m[x][y];
REP(y2,n+1)m[x][y2]-=z*m[y][y2];
}
}
//debug(m);
ret.resize(n);
REP(x,n) ret[x]=m[x][n];
return true;
}
mint get(ll n){
int k=q.size();
matrix<mint> m(k,k);
REP(x,k) REP(y,k) if(y==x+1) m[x][y]=1;
REP(y,k) m[k-1][y]=q[y];
m=m.pow(n);
mint ans=0;
REP(y,k) ans+=m[0][y]*q_init[y];
return ans;
}
};
使用例 SRM521 Div1HARD
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <cstring>
#include <assert.h>
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define ALL(s) (s).begin(),(s).end
#define clr(a) memset((a),0,sizeof(a))
#define nclr(a) memset((a),-1,sizeof(a))
#define pb push_back
#define INRANGE(x,s,e) ((s)<=(x) && (x)<(e))
#define MP(a,b) make_pair((a),(b))
using namespace std;
// BEGIN CUT HERE
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl;
#define deb(x) cerr << #x << " = " << (x) << " , ";
#define debl cerr << " (L" << __LINE__ << ")"<< endl;
template<typename T> std::ostream& operator<<(std::ostream& os, const vector<T>& z){
os << "[ ";REP(i,z.size())os << z[i] << ", " ;return ( os << "]" << endl);}
template<typename T> std::ostream& operator<<(std::ostream& os, const set<T>& z){
os << "set( "; EACH(p,z)os << (*p) << ", " ;return ( os << ")" << endl);}
template<typename T,typename U> std::ostream& operator<<(std::ostream& os, const map<T,U>& z){
os << "{ "; EACH(p,z)os << (p->first) << ": " << (p->second) << ", " ;return ( os << "}" << endl);}
template<typename T,typename U> std::ostream& operator<<(std::ostream& os, const pair<T,U>& z){
return ( os << "(" << z.first << ", " << z.second << ",)" );}
// END CUT HERE
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<long long, long long> pll;
typedef vector<int> vi;
typedef vector<vector<int> > vvi;
typedef vector<long long> vl;
typedef vector<vector<long long> > vvl;
typedef vector<double> vd;
typedef vector<vector<double> > vvd;
typedef vector<string> vs;
ll mod=1000000007;
struct mint{
ll value;
mint():value(0){}
mint(ll v):value((v%mod+mod)%mod){}
};
mint& operator+=(mint&a, mint b){return a=a.value+b.value;}
mint& operator-=(mint&a, mint b){return a=a.value-b.value;}
mint& operator*=(mint&a, mint b){return a=a.value*b.value;}
mint operator+(mint a, mint b){return a+=b;}
mint operator-(mint a, mint b){return a-=b;}
mint operator*(mint a, mint b){return a*=b;}
mint operator-(mint a){return 0-a;}
bool operator==(mint a, mint b){return a.value==b.value;}
bool operator!=(mint a, mint b){return a.value!=b.value;}
std::ostream& operator<<(std::ostream& os, const mint& m){
return ( os << m.value );}
ll extgcd(ll a, ll b, ll &x, ll &y){
ll d=a;
if(b!=0){
d=extgcd(b, a%b, y, x);
y-=(a/b)*x;
}
else{
x=1,y=0;
}
return d;
}
ll modinverse(ll a, ll b){
ll x,y;
ll d=extgcd(a,b, x, y);
assert(d==1);
return (x%b+b)%b;
}
mint& operator/=(mint&a, mint b){return a=a.value*modinverse(b.value,mod);}
mint operator/(mint a, mint b){return a/=b;}
template <typename T> struct matrix : vector<vector<T > >{
matrix(int n){
vector<vector<T> >::clear();
resize(n, vector<T>(n) );
REP(i,n) (*this)[i][i]=1;
}
matrix(int n, int m){
vector<vector<T> >::clear();
resize(n, vector<T>(m) );
}
matrix<T> operator*(const matrix<T> &b){
int n1=this->size(), n2=b.size(), n3=b[0].size();
assert(this->size()==n2);
matrix<T> ret(n1,n3);
REP(i,n1) REP(j,n3) REP(k,n2) ret[i][j]=ret[i][j]+(*this)[i][k]*b[k][j];
return ret;
}
matrix<T> pow(ll n){
int m=this->size();
assert((*this)[0].size()==m);
return pow2(matrix<T>(m) ,n);
}
matrix<T> pow2(matrix t, ll n){
if(n==0)return t;
if(n%2==0)return ((*this)*(*this)).pow2( t, n/2);
else return ((*this)*(*this)).pow2 ((*this)*t, n/2);
}
/*T det(){
int n=this->size();
vector<vector<T> >x;
REP(i,n) x.pb((*this)[i]);
T h=1;
REP(i,n){
FOR(j,i,n){
if(x[j][i]!=0 && j!=i){
REP(k,n)swap(x[j][k], x[i][k]);
h*=-1;
break;
}
}
if(x[i][i]==0)return 0;
T v=1/x[i][i];
h=h*x[i][i];
FOR(j,i+1,n){
T v2=v*x[j][i];
REP(k,n) x[j][k]=x[j][k]-x[i][k]*v2;
}
}
return h;
}*/
};
struct EST{
EST(){};
vector<mint> q_init;
vector<mint> q;
void build(vector<mint> given){
q_init=given;
int n=given.size()/2;
for(int k=0; k<=n; k++){
vector<mint> a(given.begin(), given.begin()+2*k);
bool b=build_partial(a, q);
//deb(k);deb(b);debl;
}
//debug(q);
//debug(q.size());
}
bool build_partial(vector<mint> a, vector<mint> &ret){
assert(a.size()%2==0);
int n=a.size()/2;
vector<vector<mint> > m(n, vector<mint>(n+1));
REP(i,n) REP(j,n+1) m[i][j]=a[i+j];
REP(y,n){
FOR(x,y,n) if(m[x][y]!=0){
REP(y2,n+1) swap(m[y][y2], m[x][y2]);
break;
}
if(m[y][y]==0)return false;
{
mint z=m[y][y];
REP(y2,n+1) m[y][y2]/=z;
}
assert(m[y][y]==1);
REP(x,n){
if(x==y)continue;
mint z=m[x][y];
REP(y2,n+1)m[x][y2]-=z*m[y][y2];
}
}
//debug(m);
ret.resize(n);
REP(x,n) ret[x]=m[x][n];
return true;
}
mint get(ll n){
int k=q.size();
matrix<mint> m(k,k);
REP(x,k) REP(y,k) if(y==x+1) m[x][y]=1;
REP(y,k) m[k-1][y]=q[y];
m=m.pow(n);
mint ans=0;
REP(y,k) ans+=m[0][y]*q_init[y];
return ans;
}
};
map<vi, mint> memo;
mint rec(vi z){
if(EXIST(memo,z)) return memo[z];
mint&ret=memo[z];
int tot=0;
REP(i,z.size()) tot+=z[i];
if(tot==0) return ret=1;
mint ans=0;
REP(i1,8){
int i2=(i1+1)%8;
if(z[i1]==z[i2] && z[i1]>=1 && z[i1]%2==i1%2){
vi nz=z;
nz[i1]--;
nz[i2]--;
ans+=rec(nz);
}
}
return ret=ans;
}
class Chimney {
public:
int countWays(long long n) {
vector<mint> a;
REP(i,10) a.pb(rec(vi(8,i)));
//debug(a);
EST est;
est.build(a);
int ans=est.get(n).value;
return ans;
}
};
使用例その2(SRM544Div1HAARD)
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <cstring>
#include <assert.h>
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define ALL(s) (s).begin(),(s).end
#define clr(a) memset((a),0,sizeof(a))
#define nclr(a) memset((a),-1,sizeof(a))
#define pb push_back
#define INRANGE(x,s,e) ((s)<=(x) && (x)<(e))
#define MP(a,b) make_pair((a),(b))
using namespace std;
// BEGIN CUT HERE
#define debug(x) cerr << #x << " = " << (x) << " (L" << __LINE__ << ")" << " " << __FILE__ << endl;
#define deb(x) cerr << #x << " = " << (x) << " , ";
#define debl cerr << " (L" << __LINE__ << ")"<< endl;
template<typename T> std::ostream& operator<<(std::ostream& os, const vector<T>& z){
os << "[ ";REP(i,z.size())os << z[i] << ", " ;return ( os << "]" << endl);}
template<typename T> std::ostream& operator<<(std::ostream& os, const set<T>& z){
os << "set( "; EACH(p,z)os << (*p) << ", " ;return ( os << ")" << endl);}
template<typename T,typename U> std::ostream& operator<<(std::ostream& os, const map<T,U>& z){
os << "{ "; EACH(p,z)os << (p->first) << ": " << (p->second) << ", " ;return ( os << "}" << endl);}
template<typename T,typename U> std::ostream& operator<<(std::ostream& os, const pair<T,U>& z){
return ( os << "(" << z.first << ", " << z.second << ",)" );}
// END CUT HERE
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<long long, long long> pll;
typedef vector<int> vi;
typedef vector<vector<int> > vvi;
typedef vector<long long> vl;
typedef vector<vector<long long> > vvl;
typedef vector<double> vd;
typedef vector<vector<double> > vvd;
typedef vector<string> vs;
ll mod=1000000007;
struct mint{
ll value;
mint():value(0){}
mint(ll v):value((v%mod+mod)%mod){}
};
mint& operator+=(mint&a, mint b){return a=a.value+b.value;}
mint& operator-=(mint&a, mint b){return a=a.value-b.value;}
mint& operator*=(mint&a, mint b){return a=a.value*b.value;}
mint operator+(mint a, mint b){return a+=b;}
mint operator-(mint a, mint b){return a-=b;}
mint operator*(mint a, mint b){return a*=b;}
mint operator-(mint a){return 0-a;}
bool operator==(mint a, mint b){return a.value==b.value;}
bool operator!=(mint a, mint b){return a.value!=b.value;}
std::ostream& operator<<(std::ostream& os, const mint& m){
return ( os << m.value );}
ll extgcd(ll a, ll b, ll &x, ll &y){
ll d=a;
if(b!=0){
d=extgcd(b, a%b, y, x);
y-=(a/b)*x;
}
else{
x=1,y=0;
}
return d;
}
ll modinverse(ll a, ll b){
ll x,y;
ll d=extgcd(a,b, x, y);
assert(d==1);
return (x%b+b)%b;
}
mint& operator/=(mint&a, mint b){return a=a.value*modinverse(b.value,mod);}
mint operator/(mint a, mint b){return a/=b;}
template <typename T> struct matrix : vector<vector<T > >{
matrix(int n){
vector<vector<T> >::clear();
resize(n, vector<T>(n) );
REP(i,n) (*this)[i][i]=1;
}
matrix(int n, int m){
vector<vector<T> >::clear();
resize(n, vector<T>(m) );
}
matrix<T> operator*(const matrix<T> &b){
int n1=this->size(), n2=b.size(), n3=b[0].size();
assert(this->size()==n2);
matrix<T> ret(n1,n3);
REP(i,n1) REP(j,n3) REP(k,n2) ret[i][j]=ret[i][j]+(*this)[i][k]*b[k][j];
return ret;
}
matrix<T> pow(ll n){
int m=this->size();
assert((*this)[0].size()==m);
return pow2(matrix<T>(m) ,n);
}
matrix<T> pow2(matrix t, ll n){
if(n==0)return t;
if(n%2==0)return ((*this)*(*this)).pow2( t, n/2);
else return ((*this)*(*this)).pow2 ((*this)*t, n/2);
}
/*T det(){
int n=this->size();
vector<vector<T> >x;
REP(i,n) x.pb((*this)[i]);
T h=1;
REP(i,n){
FOR(j,i,n){
if(x[j][i]!=0 && j!=i){
REP(k,n)swap(x[j][k], x[i][k]);
h*=-1;
break;
}
}
if(x[i][i]==0)return 0;
T v=1/x[i][i];
h=h*x[i][i];
FOR(j,i+1,n){
T v2=v*x[j][i];
REP(k,n) x[j][k]=x[j][k]-x[i][k]*v2;
}
}
return h;
}*/
};
struct EST{
EST(){};
vector<mint> q_init;
vector<mint> q;
void build(vector<mint> given){
q_init=given;
int n=given.size()/2;
for(int k=0; k<=n; k++){
vector<mint> a(given.begin(), given.begin()+2*k);
bool b=build_partial(a, q);
//deb(k);deb(b);debl;
}
//debug(q);
//debug(q.size());
if(q.size()==0){
q.pb(0);
}
}
bool build_partial(vector<mint> a, vector<mint> &ret){
assert(a.size()%2==0);
int n=a.size()/2;
vector<vector<mint> > m(n, vector<mint>(n+1));
REP(i,n) REP(j,n+1) m[i][j]=a[i+j];
REP(y,n){
FOR(x,y,n) if(m[x][y]!=0){
REP(y2,n+1) swap(m[y][y2], m[x][y2]);
break;
}
if(m[y][y]==0)return false;
{
mint z=m[y][y];
REP(y2,n+1) m[y][y2]/=z;
}
assert(m[y][y]==1);
REP(x,n){
if(x==y)continue;
mint z=m[x][y];
REP(y2,n+1)m[x][y2]-=z*m[y][y2];
}
}
//debug(m);
ret.resize(n);
REP(x,n) ret[x]=m[x][n];
return true;
}
mint get(ll n){
int k=q.size();
matrix<mint> m(k,k);
REP(x,k) REP(y,k) if(y==x+1) m[x][y]=1;
REP(y,k) m[k-1][y]=q[y];
m=m.pow(n);
mint ans=0;
REP(y,k) ans+=m[0][y]*q_init[y];
return ans;
}
};
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
class SplittingFoxes {
public:
int sum(long long n, int S, int L, int R) {
map<vi, mint> z;
vi init(3,0);
z[init]=1;
vector<mint> a;
REP(i,10){
//debug(z);
mint tot=0;
EACH(pp,z){
int x=pp->first[0];
int y=pp->first[1];
int r=pp->first[2];
tot+=x*y*pp->second;
}
a.pb(tot);
map<vi, mint> nz;
EACH(pp,z){
int x=pp->first[0];
int y=pp->first[1];
int r=pp->first[2];
mint v=pp->second;
REP(k,3){
int nx=x,ny=y,nr=r;
if(k==0){
nx+=dx[r];
ny+=dy[r];
}
if(k==1)nr++;
if(k==2)nr+=3;
nr%=4;
vi p(3);
p[0]=nx;
p[1]=ny;
p[2]=nr;
int weight[3]={S,L,R};
nz[p]+=weight[k]*v;
}
}
z=nz;
}
//debug(a);
//debug(n);
EST est;
est.build(a);
int ans=est.get(n).value;
return ans;
}
};
最終更新:2014年02月19日 00:47