题意:
一个无向图,从起点出发,T时间内要到达终点。所有点都有一个景观值,可以游览,但是游览需要额外的时间,而且游览的景点的游览值必须比前一次要大。求最大的游览值和。
题解:
按游览值排序,用一个dp[i][j]数组表示j时间游览了i的最大游览值和。只能从前面的游览值比i小的转移。注意是从起点出发的,最后要到终点(游览终点的话时间也要算在T内)。
//Time:156ms
//Memory:360KB
//Length:1520B
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define MAXN 110
#define FI first
#define SE second
using namespace std;
long long toz(long long n,long long mod)
{
if(n>0) return n%mod;
else return mod-(-n)%mod;
}
void mul(long long a[2][2],long long b[2][2],long long mod)
{
long long tmp[2][2]={{0}};
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
for(int k=0;k<2;++k)
tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%mod;
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
a[i][j]=tmp[i][j];
}
void pow_mod(long long a[2][2],long long p,long long mod)
{
long long ans[2][2]={{0}};
ans[0][0]=ans[1][1]=1;
while(p)
{
if(p&1) mul(ans,a,mod);
mul(a,a,mod);
p>>=1;
}
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
a[i][j]=ans[i][j];
}
int main()
{
//freopen("/home/moor/Code/input.txt","r",stdin);
long long a,b,n,m,c,a1,a2;
while(cin>>a>>b>>n>>m)
{
long long num[2][2];
c=toz(-a*a+b,m);
num[0][0]=2*a%m,num[0][1]=1;
num[1][0]=c,num[1][1]=0;
a1=(long long )ceil(a+sqrt(b*1.0))%m;
a2=(2*a*a+2*b)%m;
if(n>=3)
{
pow_mod(num,n-2,m);
long long tmp[2][2]={{0}};
tmp[0][0]=a2,tmp[0][1]=a1;
mul(tmp,num,m);
cout<<tmp[0][0]<<'\n';
}
else cout<<(n==1?a1:a2)<<'\n';
}
return 0;
}