[补题记录]AtCoder Beginner Contest 175 D - Moving Piece
AtCoder Beginner Contest 175 D - Moving Piece
题意:
Takahashi will play a game using a piece on an array of squares numbered \(1, 2, \cdots, N\). Square \(i\) has an integer \(C_i\) written on it. Also, he is given a permutation of \(1, 2, \cdots, N\): \(P_1, P_2, \cdots, P_N\).
Now, he will choose one square and place the piece on that square. Then, he will make the following move some number of times between \(1\) and \(K\) (inclusive):
In one move, if the piece is now on Square \(i\) \((1 \leq i \leq N)\), move it to Square \(P_i\). Here, his score increases by \(C_{P_i}\).
Help him by finding the maximum possible score at the end of the game. (The score is \(0\) at the beginning of the game.)
给你两组序列\(N,P\),每次对于\(1\)到\(n\)的每一个\(i\)你要把Square \(i\)移到 Square \(P_i\),然后\(i\)的score会增长\(C_{p_i}\),问在这场游戏中能达到的最大score
题解:
首先\(k\leq 10^9\)我们肯定不能模拟,按照样例推导一遍是会发现它是有循环节的,也就是说问题简化为了对于每一个\(i\),有\(a_1,a_1+a_2,\dots,a_1+a_2+a_3+\dots+a_{temp}+a_1+a_2+a_3+\dots\)(一共k项)中出现过的数的最大值
那么我们对于每一个\(i\),把一个循环结存到ve[i]中,ve[i].size()就是循环节的大小
然后记下来\(d=k/len\)最多跑多少个循环节 \(m=k%len\) 最后一个循环节多出来多少个数
如果一个循环节的总和>0,那我们一定是要把所有的循环节跑完的
now=d*sum[i];
for(int j=0;j<m;j++) now+=ve[i][j],ans=max(ans,now);
还有就是如果\(m==0\),那\(d--;m=len;\)保留最后一次循环节
如果一个循环节的总和<=0,那我们选了这个循环节还不如不选,只对\(0\)到\(d==0?m:ve[i].size()\)取个最优即可
唔 貌似别忘了还要开个long long
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lowbit(a) ((a) & -(a))
#define clean(a, b) memset(a, b, sizeof(a))
const int mod = 998244353;
const int inf = 0x3f3f3f3f;
const int maxn = 2e5 + 9;
// typedef pair<int,int>P;
int _;
//========================================================================
ll Pp[maxn],Cc[maxn],mp[5009];
ll a[maxn],sum[maxn];
vector<ll>ve[5009];
//========================================================================
int main()
{
ll n,k;
ll x;
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
Pp[i]=a[i];
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
Cc[i]=x;
}
ll ans=-1e18;
for(ll i=1;i<=n;i++)
{
ll now=i;
clean(mp,0);
while(1)
{
now=Pp[now];
if(mp[now]==1) break;
mp[now]=1;
sum[i]+=Cc[now];
ve[i].push_back(Cc[now]);
}
int len=ve[i].size();
ll d=k/len;
ll m=k%len;
now=0;
if(sum[i]>0)
{
if(m==0)
{
now=(d-1)*sum[i];
m=len;
}
else now=d*sum[i];
for(int j=0;j<m;j++) now+=ve[i][j],ans=max(ans,now);
}
else
{
if(d==0)
{
for(int j=0;j<m;j++) now+=ve[i][j],ans=max(ans,now);
}
else
{
for(int j=0;j<len;j++) now+=ve[i][j],ans=max(ans,now);
}
}
}
// for(int i=1;i<=n;i++)
// {
// int len=ve[i].size();
// for(int j=0;j<len;j++) printf("%lld ",ve[i][j]);
// printf("\n");
// }
printf("%lld\n",ans);
return 0;
}