题目描述:
这个游戏是这样的,你有一个初始序列S ,你每次可以选择一段任意长度的连续区间,把他们+1 再膜k,给定目标序列,你需要尝试用尽量少的操作次数将初始序列变为目标序列。作为一名优秀的OIer,您认为这个游戏十分naive,所以您打算撸一个游戏脚本来取到最优解。
输入:
第一行一个T 表示数据组数。
对于每组数据,第一行两个整数表示序列长度和模数。
接下来两行分别包含n 个整数,表示初始序列和目标序列。
输出:
对于每组数据,输出一行一个整数表示最少操作次数。
数据范围:
1<=T<=5
对于10% 的数据满足n≤1
对于30% 的数据满足n≤10
对于50% 的数据满足n≤100
对于70% 的数据满足n≤5000
对于100% 的数据满足1≤n≤100000,1≤k≤100,0≤x1≤n≤100000,1≤k≤100,0≤x(序列中的任一数)<k
算法标签:差分&桶排
思路:
片段共同加1可以想到差分,倘若没有%k,我们可以直接差分之后每次取ans+=max(0,c[i])。加了%k之后,当我们某一段值+k时对于差分的数组的影响是头c[i]+k,尾的c[i]-k。于是我们可以用桶存c[i]+k的值然后每次取最小值不断贪心。
以下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include#define il inline#define _(d) while(d(isdigit(ch=getchar())))using namespace std;const int N=1e5+5;int a[N],b[N],c[N],maxn,t[N],ans,k,n;il int read(){ int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}il int get(int x){ return abs(c[x-1]-c[x])+abs(c[x+1]-c[x]);}int main(){ int T=read();while(T--){ n=read();ans=0;k=read(); for(int i=1;i<=n;i++)a[i]=read();for(int i=1;i<=n;i++)b[i]=read(); for(int i=0;i<=k;i++)t[i]=0; for(int i=1;i<=n;i++){ if(b[i]>=a[i])c[i]=b[i]-a[i]; else c[i]=b[i]+k-a[i]; } for(int i=n;i;i--)c[i]=c[i]-c[i-1]; for(int i=1;i<=n;i++){ int tot=0; if(c[i]>0){ for(int j=1;j