牛客练习赛44 B题 (思维)

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

给出n条线段,第i条线段的长度为ai,
每次可以从第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

备注:
1≤n≤2×1e7
1≤mod≤6662333

     

题意:(如上,a数组非键盘输入得到,而是调用上列已给函数得到a数组)

思路: 如果线段之间跳跃中不存在归零的跳法,则ans=(1+2+3+.....(n-1))  =    n*(n-1) / 2,

  而真正的答案是ans=正常跳数+归零跳数。正常的跳数,已被求得,那么只需要再求出归零跳数即可。

  至于如何求归零跳数,逆向思维即可。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<queue>
#include<stack>
#include<algorithm>
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
#define Mem0(x) memset(x,0,sizeof(x))
#define Mem1(x) memset(x,-1,sizeof(x))
#define MemX(x) memset(x,0x3f,sizeof(x))
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f;
const double pi=acos(-1.0);

ll n,a[20000010];
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;
    ll ans;
    if (n&1)
        ans=(n-1)/2*n;
    else
        ans=n/2*(n-1);
    ll tmp=a[n],cnt=0;
    for (int i=n-1;i>=1;i--){
        tmp--;
        tmp=min(a[i],tmp);
        if (tmp==0){
            cnt=cnt+(i-1);   //第i线段以上的线段在这里都要执行归零跳法
            tmp=a[i];
        }
            
    }
    cout<<ans+cnt<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/q1204675546/p/10744504.html