这个游戏是这样的,你有一个初始序列S ,你每次能够选择一段任意长度的连续区间,把他们+1 再膜k,给定目标序列,你须要尝试用尽可能少的操做次数将初始序列变为目标序列。做为一名优秀的OIer,您认为这个游戏十分naive,因此您打算撸一个游戏脚原本取到最优解。php
第一行一个T 表示数据组数。ios
对于每组数据,第一行两个整数表示序列长度和模数。spa
接下来两行分别包含n 个整数,表示初始序列和目标序列。code
对于每组数据,输出一行一个整数表示最少操做次数。blog
<span style="color:#333333"><span style="color:#333333">1 6 4 1 1 3 2 0 2 2 0 2 3 2 0</span></span>
<span style="color:#333333"><span style="color:#333333">4</span></span>
样例解释游戏
四次操做的一种方式为:(1,6)(2,3)(2,3)(5,6)ip
数据范围ci
1≤T≤51≤T≤5get
对于10% 的数据知足n≤1n≤1string
对于30% 的数据知足n≤10n≤10
对于50% 的数据知足n≤100n≤100
对于70% 的数据知足n≤5000n≤5000
对于100% 的数据知足1≤n≤100000,1≤k≤100,0≤x1≤n≤100000,1≤k≤100,0≤x(序列中的任一数)<k<k
solution
首先咱们能够求出每个位置须要操做几回。
设为a[i].记c[i]=a[i]-a[i-1]
咱们能够把a[i]的连续一段加上k
至关于把位置+k 另外一个位置-k
咱们应该要把一个大于零的减掉k,小于零的加k使答案更优
因而用一个桶存下小于零的,每次取尽可能小便可
#include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<cmath> #define maxn 100005 using namespace std; int T,n,k,a[maxn],t,f[maxn],g[maxn],c[maxn],tax[202],ans; int main() { cin>>T; while(T--){ scanf("%d%d",&n,&k); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++){ scanf("%d",&t); int ne=t-a[i];ne=(ne+k)%k; a[i]=ne; } a[0]=0; for(int i=1;i<=n;i++)c[i]=a[i]-a[i-1];ans=0; memset(tax,0,sizeof tax); for(int i=1;i<=n;i++){ if(c[i]<0)tax[c[i]+k]++; else { bool fl=0; for(int j=0;j<c[i];j++)if(tax[j]){ tax[j]--;tax[c[i]]++; ans=ans+j; fl=1;break; } if(!fl)ans=ans+c[i]; } } cout<<ans<<endl; } return 0; }