【GDOI2018】D1T2 密码锁(lock) - 差分 - 贪心
题目大意
给出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; }