這個遊戲是這樣的,你有一個初始序列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; }