链接:https://ac.nowcoder.com/acm/contest/634/B
来源:牛客网

题目描述
给出n条线段,第i条线段的长度为a_ia
i

,每次可以从第i条线段的j位置跳到第i + 1条线段的j+1位置。如果第i+1条线段长度不到j+1,那么就会回到第i条线段的0位置,然后继续跳。
问从第i条线段的0位置跳到第n条线段需要跳多少次
为了减少输入量,a数组将由以下方式得到
unsigned int SA, SB, SC;
int mod;
unsigned int Rand(){
SA ^= SA << 16;
SA ^= SA >> 5;
SA ^= SA << 1;
unsigned int t = SA;
SA = SB;
SB = SC;
SC ^= t ^ SA;
return SC;
}
int main() {
cin>>n>>mod>>SA>>SB>>SC;
for(int i = 1;i <= n;++i) a[i] = Rand() % mod + 1;
}
输入描述:
第一行两个正整数n,mod,表示一共有n条线段

第二行3个数字,分别为SA,SB,SC
输出描述:
一行一个数字,表示从每条线段跳到n的次数之和。
示例1
输入
复制
5 5
5 6 4
输出
复制
13

思路:

假设每一个a[i] 都无限长的话, 那么ans = n * ( n-1 ) / 2

然后我们思考多出的跳跃是从哪里来的呢?

是当如果第i+1条线段长度不到j+1,那么就会回到第i条线段的0位置,这里就会多跳一次。

那么我们可以知道,如果一个位置i,走到第j个线段会跳到0位置的话,那么i以上的所有线段都会因为i到j 之间线段长度的限制多跳跃一次, (可以画图理解一下。)

然后我们就可以 从后向前倒推,看那些i符合上面的情况,对答案做累加即可。

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2) { ans = ans * a % MOD; } a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int *p);
const int maxn = 20000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
unsigned int SA, SB, SC;
int mod;
int n;
unsigned int a[maxn];
unsigned int Rand()
{
    SA ^= SA << 16;
    SA ^= SA >> 5;
    SA ^= SA << 1;
    unsigned int t = SA;
    SA = SB;
    SB = SC;
    SC ^= t ^ SA;
    return SC;
}
int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);


    cin >> n >> mod >> SA >> SB >> SC;
    for (int i = 1; i <= n; ++i) { a[i] = Rand() % mod + 1; }

    ll ans=(n*(n-1))/2;
    ll x=a[n];
    for(int i=n-1;i>=1;--i)
    {
        x--;
        if(x>a[i])
        {
            x=a[i];// 取较小的作为限制条件
        }
        if(!x)
        {
            ans+=(i-1);// 这个位置前面的每一个线段都会多跳一次。
            x=a[i];
        }
    }
    cout<<ans<<endl;

    return 0;
}

inline void getInt(int *p)
{
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    } else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}