ABC258E(找循环节)

ABC258E(找循环节)

思路很简单,主要代码很不好写。官方题解的写法很好。

先暴力把每一段长度算出来,然后再环上跳,用一个order数组编号,path寄一下开始结点,之后循环节就很简单能被找到。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<stack>
#include<string>
#include<random>
#include<iomanip>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
#define endl '\n'
#define int long long
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int n,q,x; cin >> n >> q >> x;
    vector<int> w(n + n);
    rep(i,0,n - 1) cin >> w[i], w[i + n] = w[i];
    ll sum = accumulate(w.begin(),w.end(),0ll) / 2;
    vector<ll> cnt(n,(x / sum) * n);
    x %= sum;
    for(int i = 0,j = 0,s = 0;i < n;i ++) {
        if(j < i) j = i,s = 0;
        while(s < x) s += w[j ++];
        cnt[i] += j - i;
        s -= w[i];
    }
    vector<int> path, ord(n,-1);
    int loop = -1;
    for(int i = 0,id = 0;;id ++) {
        if(ord[i] != -1) {
            loop = id - ord[i];
            break;
        }
        ord[i] = id;
        path.push_back(i);
        i = (i + cnt[i]) % n;
    }
    int beg = (int)path.size() - loop;
    while(q --) {
        int k; cin >> k;
        k --;
        if(k < beg) cout << cnt[path[k]] << endl;
        else {
            k = (k - beg) % loop;
            cout << cnt[path[k + beg]] << endl;
        }
    }
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    //int T;cin>>T;
    //while(T--)
        solve();

    return 0;
}
posted @ 2022-07-05 23:08  Mxrurush  阅读(47)  评论(0编辑  收藏  举报