【GDOI2018】D1T2 密码锁(lock)

假如想象 提交于 2020-05-02 07:25:25

题目大意

  给出n个数,每次选择任意一个区间加或减1,求最少多少次能在$mod m$意义下全变成0。

Solution

  首先我们对于这n个数前后加个零,在$mod m$意义下差分一下。

  $f[i]=(a[i]-a[i-1]+m)mod m$

  于是区间加减1操作就转换成了在某一位加一,另一位减一。

  容易发现,每个数只会加到m或者减到1,而不会有多次循环。

  这样我们对差分序列排个序,在前半部分选择$l$减到1,后半部分选择$r$个加到n,($l+r=n$)

  这题就没了。

AC Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
using namespace std;
#define MAXBUF 50000000
char buffer[MAXBUF];
int pos;
inline void load(){
    fread(buffer,1,MAXBUF,stdin);
    pos=0;
}
inline char gchar(){
    return buffer[pos++];
}
inline int rd(){
    int ret=0,f=1;char c=gchar();
    for(;!isdigit(c);)
        if(c=='-')f=-1,c=gchar();else c=gchar();
    for(;isdigit(c);)ret=ret*10+c-'0',c=gchar();
    return ret*f;

}
int n,m,nl,nr;
int f[500010],a[500010];
int main(){
    freopen("lock.in","r",stdin);
    load();
    n=rd();m=rd();
    for(int i=1;i<=n+1;i++)
        a[i]=rd(),
        f[i]=(a[i]-a[i-1]+m)%m;
    sort(f+1,f+n+2);
    for(int l=0,r=n+1;l<=r;)
        if(nl<=nr)
            nl+=f[l++];
        else nr+=m-f[r--];
    printf("%d\n",nl);
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!