jzoj5245 【NOIP2017模拟8.8A组】Competing Souls

题意

有n个数a[i],现在有个指针i一直1..n,1..n的循环移动,每次指针移动到i时,a[i]可以在last+1..m中选一个数x,last是上一个被选的数,满足x<=a[i]。并给ans+=x,a[i]-=x.
最后指针必须要指向n,即必须要做完整的循环。
现在给出a[i],求出最大的ans.

30%:M≤20
另有10%:N=2
100%:1≤T≤5 2≤N≤500,000 N≤M≤5,000,000 1≤a[i]≤ (m*(m+1)/2)

分析

先确定循环数(行数),先放最小的一种方案,从1开始顺次取。
想象成一个n*m的表格。

然后考虑给这个方案up。发现问题就变成了怎么才能使得每一个数的+1次数最多。因为移动一次就等于答案+1。
又因为移动收益是相等的,为了使整体移动更多,当然从尾巴开始移动(腾出空位)。
这样就能得到一个暴力算法,枚举行数i,然后每次n*i的暴力移动,直到不能移动为止。
这个复杂度是 O(mnnm) 也就是 O(m2) 的。 (我觉得这里应该给部分分)

优化

现在来优化这个算法,注意到可以移动的步数最大为m-Max.
设有p行可以被整体最大移动m-Max,设k=n-p+1即第一行可以被最大移动的。

可以证明他不被最大移动,但可以移动的行就是只有接下来两行(即第k-1,k-2行)。
因为在移动第k-1行的时候,第i列可以移动的步数其实就是一个剩余a[i]的后缀min(初始min就是m-Max).因为要后面先动前面才能动。
那么就至少有一个位置的剩余步数会被使用完毕,这样在第k-2行这个位置是无法移动的,上面所有位置都无法移动了。

这样的话计算出能移动m-Max的行数,然后暴力两行即可。

至此得到了一个复杂度为 O(mnn)=O(m) 的算法。

Code

#include <cstdio>
#define N 500100
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef long long ll;
ll T;
ll n,m,a[N],ans,mi,b[N];

int main() {
    freopen("compete.in","r",stdin);
    freopen("compete.out","w",stdout);
    for (cin>>T; T; T--) {
        cin>>n>>m; ans=0; ll pr=0;
        for (ll i=1; i<=n; i++) scanf("%lld",&a[i]);
        ll ls=m/n;
        for (ll i=1; i<=ls; i++) {
            mi=(1ll<<60); ans=(1+i*n)*i*n/2;
            for (ll j=1; j<=n; j++) a[j]-=i*n-n+j,mi=min(mi,a[j]);
            if (mi<0) break;
            ll hang=min(i,mi/(m-i*n));
            ans+=n*hang*(m-i*n);
            for (ll j=1; j<=n; j++) b[j]=a[j]-hang*(m-i*n);
            ll mib=m-i*n;
            for (ll z=i-hang; z>=i-hang-1 && z>0; z--) {
                for (ll j=n; j; --j) {
                    mib=min(b[j],mib);
                    ans+=mib;
                    b[j]-=mib;
                    if (mib==0) break;
                }
            }
            pr=max(pr,ans);
        }
        printf("%lld\n",pr);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值