Codeforces Round #760 (Div. 3) E 错位减 找性质 思维 二分爆longlong

题目

有n个地方 每个地方的唱歌时间固定值为bi

每个地方都有一个歌手ai,他在这个地方唱完后会去(i+1)mod n 的地方,并且时间加倍,也就是 ai 2ai 3ai …nai 。
他会走完所有地方。
求是否存在一个ai数组使得所有bi都成立。

题解思路

这种数列的部分和的题,第一步肯定是错位减减找性质。
可以得到 sum(a[i]) - na[i] = 差值
而sum其实是可以之前求出来的
每个歌手都唱了ai 2ai … nai
求和就是 (1 + 2 … n) sum(a[i]) == sum(b[i) 。
然后在每一步判断值的合法性即可。

枚举a[i]的二分
自己写了个二分居然过了,实际上不需要二分的。
这个二分还爆了longlong 开了int128才过的。

AC代码

正常解法

#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long

using namespace std;

const  int  INF =  0x3f3f3f3f;
const  int  N =  200100;
int n ;
long long a[N] ; 
long long sum , st , s ;
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T ;
    cin >> T ;
    while ( T-- )
    {
        s = sum = st = 0 ; 
        cin >> n ;
        for (int i = 1 ; i <= n ; i++ )
            cin >> a[i] , sum += a[i] , st += i ; 
        if ( n == 1 )
        {
            cout << "YES\n" ;
            cout << a[1] << "\n" ; 
        }else
        {
            if ( sum % st )
            {
                cout << "NO\n" ; 
            }else
            {
                s = sum/st ; 
                int falg = 1 ; 
                vector <int> ans ; 
                for (int i = 1 ; i <= n ; i++ )
                {
                    long long sp ; 
                    if ( i == 1 )
                        sp = a[1] - a[n] ;
                    else
                        sp = a[i] - a[i-1] ; 
                    if ((s - sp)%n || (s-sp)/n < 1 || (s-sp)/n > 1e9 )
                        falg = 0 ; 
                    ans.push_back((s-sp)/n) ; 
                }
                if (falg)
                {
                    cout << "YES\n" ;
                    for ( auto i : ans )
                        cout << i << " " ; 
                    cout << "\n" ; 
                }else
                    cout << "NO\n" ; 
            }
        }
    }
    return 0 ;
}

二分解法

#include <bits/stdc++.h>
//#include <unordered_map>
//priority_queue
#define PII pair<int,int>
#define ll long long

using namespace std;

const  int  INF =  0x3f3f3f3f;
const  int  N =  200100;

long long a[N] ; 
long long sum ; 
long long st ; 
long long dt ; 
int n ;

bool che(long long p )
{
    long long sm = n*p + dt ; 
    if ( (__int128)st*sm >= sum )
        return 1 ;
    else
        return 0 ; 
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int T ;
    cin >> T ;
    while ( T-- )
    {   
        sum = st = 0 ; 
        cin >> n ;
        for (int i = 1 ; i <= n ; i++ )
            cin >> a[i] , sum += a[i] , st += i ; 
        if ( n == 1 )
        {
            cout << "YES\n" ; 
            cout << a[1] << "\n" ; 
        }else
        {
            long long t1 = 1 , t2 = 1e9 + 7 ;
            dt = a[1] - a[n] ; 
            while ( t1 < t2 )
            {
                long long mid = t1 + t2 >> 1 ;
                if (che(mid))
                {
                    t2 = mid ; 
                }else
                    t1 = mid + 1 ; 
            }
            if ( st*(n*t2 + dt)  == sum )
            {
                int falg = 1 ;
                vector <int> ans ; 
                if ( t2 < 1 || t2 > 1e9 )
                    falg = 0 ; 
                ans.push_back(t2) ; 
                long long sk = n*t2 + dt ; 
                for (int i = 2 ; i <= n ; i++ ) 
                {
                    long long ff = ( sk - (a[i] - a[i-1] )) ; 
                    if ( ff % n )
                        falg = 0 ; 
                    if ( ff/n < 1 || ff/n > 1e9 )
                        falg = 0 ; 
                    ans.push_back(( sk - (a[i] - a[i-1] ))/n) ; 
                }
                if ( falg )
                {
                    cout << "YES\n" ; 
                    for ( auto i : ans )
                        cout << i << " ";
                    cout << "\n" ; 
                }else
                    cout << "NO\n" ; 
            }else
            {
                cout << "NO\n" ; 
            }
        }
    }
    return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值