题目地址
思路:假定我们已经得到了k的值,那么最终的 \(f_i\) 中必然有一个值等于 \(k*max(v)\) 而且必然是 \(f_i\) 的最大值,那就好做了,找到 \(v_i\) 和 \(f_i\) 的最大值,除一下k就出来了,现在要验证这个k是否合法,也就是我要根据这个k,算出买k个物品,对于每种模数价格的价值最大值是否和 \(f_i\) 完全一样。这个我们可以考虑生成函数,其中指数表示价格,系数表示价值,那么买一个物品的生成函数如下。
\(v_n+v_1x^1+v_2x^2+...+v_{n-1}x^{n-1}\)
那么买k个物品就是该生成函数的k次方,注意,由于这题对价格要对n取模,同时价值是相加而不是相乘,所以不是传统的卷积,而是 \(f_{k}=max((f_i+f_j)[(i+j)\%n==k])\) 所以快速幂的时候手写mul函数要注意是加法。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <time.h>
#include <map>
#include <algorithm>
#include <fstream>
//#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 400000 + 100;
const int INF = 0x7fffffff;
const ll mod = 998244353;
const ll mod1 = 998244353;
const ll base = 137;
const double Pi = acos(-1.0);
const int G = 3;
int v[maxn];
ll f[maxn];
vector<ll>a;
int n;
vector<ll> mul(vector<ll>a,vector<ll>b)
{
vector<ll>res(n,-4e18);
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
res[(i+j)%n]=max(res[(i+j)%n],a[i]+b[j]);
}
}
return res;
}
vector<ll>add(vector<ll>a,vector<ll>b)
{
for(int i=0;i<n;i++)
{
a[i]+=b[i];
}
return a;
}
vector<ll> q_pow(vector<ll>a,ll b)
{
vector<ll>res(n,0);
int f=0;
//res[0]=1;
while(b)
{
if(b&1)
{
if(!f)
{
for(int j=0;j<n;j++) res[j]=a[j];
f=1;
}
else
{
res=mul(res,a);
}
/* for(int j=0;j<n;j++)
{
cout<<a[j]<<' ';
}
puts("");*/
}
b>>=1;
a=mul(a,a);
}
return res;
}
int main()
{
scanf("%d",&n);
int mx1=-1000000000;
ll mx2=-1000000000000000000;
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
mx1=max(mx1,v[i]);
}
for(int i=0;i<n;i++)
{
scanf("%lld",&f[i]);
mx2=max(mx2,f[i]);
}
ll k=mx2/mx1;
if(mx2%mx1||k<1||k>1000000000)
{
puts("-1");
return 0;
}
// cout<<k<<endl;
a.push_back(v[n]);
for(int i=1;i<=n-1;i++)
{
a.push_back(v[i]);
}
vector<ll>res=q_pow(a,k);
int flag=1;
for(int i=0;i<n;i++)
{
// cout<<i<<' '<<res[i]<<endl;
if(res[i]!=f[i])
{
flag=0;
}
}
if(flag)
{
cout<<k<<endl;
}
else puts("-1");
//system("pause");
}