AtCoder Beginner Contest 241(Sponsored by Panasonic)
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
LL n, k;
LL a[N], id[N], s[N], st, ed;
//同余性质
//若 a mod n == b mod n
//则 a+x mod n == b+x mod n
//x%n的结果一定在0~n-1之间
//若k>n一定会出现重复余数
//当第一次出现重复的下标(对应相同增量)时 循环开始
//id数组记录x%n得出的下标第一次出现的位置
//s维护迭代过程中的前缀和
//当x%n得出的下标第二次出现时 迭代路径形成一个环 且此后始终在环中
int main()
{
LL n, k;
cin >> n >> k;
for (int i = 0;i < n;i++)scanf("%lld", &a[i]);
for (int i = 0;i < n;i++)id[i] = -1;//期初所有点都没有出现过
id[0] = 0;//x初始值是0 0出现过
for (int i = 0;i < n;i++)
{
s[i + 1] = s[i] + a[s[i] % n];
if (id[s[i + 1] % n] != -1)//若如今得到的新下标出现过
{
st = id[s[i + 1] % n];//循环的开始是上一次出现
ed = i + 1;//循环的结束是现在
break;
}
id[s[i + 1] % n] = i + 1;//记录当前下标第一次出现的位置
}
LL ans = 0;
if (k <= st)
{
ans = s[k];
}
else
{
LL len = ed - st;//环的长度是终止位置减去起始位置
LL val = s[ed] - s[st];//循环一次的总增量
//计算与环的起点相比多走了多少步
LL times = (k - st) / len;//走了几遍环
LL left = (k - st) % len;//剩下的
ans = times * val + s[st + left];
}
cout << ans;
return 0;
}