1. 程式人生 > 實用技巧 >一道codeforces題目引發的差分學習

一道codeforces題目引發的差分學習

Codeforces Round #688 (Div. 2)

題目:B. Suffix Operations

題意:給定一個長為n的陣列a,你可以進行兩種操作:1).字尾+1; 2)字尾-1; 問需要最少多少步操作你才能使得陣列中元素全部相等,並且首先你可以改變其中任何一個元素成為任何一個數,並且不被計入步數

思路:

首先來看一下陣列中大致分為這三種情況:舉例

3 5 7 (上升式)這樣中間的5變成3-7之間的任何一個數都能最終變成3

7 5 3 (下降式)與上述相同

7 3 5 (斷崖式)最終要讓他變成7,會產生浮動變化

通過上面的例子,就想到會用到差分陣列(d[n]),總共的浮動次數是不變的,只需要統計如果一個數變化的時候影響最大的次數是多少,因為最終肯定會是出現階段性的後面的數要變成它前面的數,所以要分情況討論d[i]變化引起的d[i+1]的變化,具體看程式碼

程式碼:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<map>
 7 #include<queue>
 8 using namespace std;
 9 const int maxx=2e5+1;//14.12
10 //找差分
11 long long int a[maxx]={0};
12 long long int d[maxx]={0
}; 13 int main(){ 14 int n; 15 scanf("%d",&n); 16 while(n--){ 17 int m; 18 scanf("%d",&m); 19 20 long long int sum=0; 21 for(int i=1;i<=m;i++){ 22 scanf("%lld",&a[i]); 23 d[i]=a[i]-a[i-1];//差分陣列 24 if(i>1){
25 26 sum+=abs(d[i]); 27 } 28 } 29 30 long long int maxn=0; 31 for(int i=1;i<=m;i++){ 32 long long int x=abs(d[i]),y=abs(d[i+1]); 33 if(i==1){ 34 maxn=max(maxn,abs(d[2])); 35 }else if(i==m){ 36 maxn=max(maxn,abs(d[m])); 37 }else{ 38 long long int y1; 39 if(d[i]>0){ 40 y1=d[i+1]+x; 41 }else{ 42 y1=d[i+1]-x; 43 } 44 maxn=max(maxn,x+y-abs(y1)); 45 } 46 } 47 sum-=maxn; 48 printf("%lld\n",sum); 49 50 51 } 52 }
View Code

差分陣列/字首和的應用:

主要就是對陣列中的數字進行操作,通過小區間波動改變一整個陣列

1.HDU-1556 Color the Ballhttp://acm.hdu.edu.cn/showproblem.php?pid=1556

思路:一開始以為直接用a[maxx]陣列進行遍歷迴圈就行,結果TLE掉了,時間複雜度是O(n2),結果看了看並沒有這麼簡單,應該是用兩個陣列,一個儲存實際值(顯然初始值都是0)c[n],一個儲存浮動變化d[n]

d:0 1 0 0 -1

c:0 1 1 1 0

這樣看來也有一些逆向字首和的想法,儲存的時候先儲存d[i],然後按照字首和的想法進行輸出,這樣時間複雜度就是O(n)

程式碼:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<cstring>
 6 #include<map>
 7 #include<queue>
 8 using namespace std;
 9 const int maxx=2e5+1;//14.12
10 int main(){
11     int n;
12     while(~scanf("%d",&n)){
13         int a[maxx]={0};
14         if(n==0){
15             break;
16         }
17         int c[maxx]={0};
18         for(int i=1;i<=n;i++){
19             int t,b;
20             scanf("%d %d",&t,&b);
21             c[t]++;
22             c[b+1]--;
23         }
24         int sum=0;
25         for(int i=1;i<=n;i++){
26             sum+=c[i];
27             printf("%d",sum);
28             if(i<n){
29                 printf(" ");
30             }
31         }
32         printf("\n");
33     }
34 }
View Code

2.POJ -3263 Tallest Cowhttp://poj.org/problem?id=3263

思路:一開始想著用陣列的加加減減,還是所有的從0開始,看他們的相對大小就好了,結果發現做的時候兩邊端點都加加,中間的都減減,這樣出來的結果就是錯的,後來發現差分陣列想錯了,並不是這樣,而且這樣也會TLE掉,這個題目中問的是最高多少,而且同時加減這樣端點和中間就會差2而不是1,所以讓所有的牛最初始的高度是h,然後再建立一個數組b[n]儲存差分值,x,y為區間端點,b[x+1]--,b[y]++,而且這個題還需要區間判重一下,見程式碼

程式碼:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<string>
 6 #include<cmath>
 7 #define ll long long
 8 #define mem(a,b) memset(a,b,sizeof(a))
 9 using namespace std;
10 const int inf=0x3f3f3f3f;
11 const int mm=1e4+10;
12 int a[mm],b[mm];
13 int vis[mm][mm];
14 int main(){
15     int n,pos,h,r;
16     scanf("%d%d%d%d",&n,&pos,&h,&r);
17     for(int i=0;i<=h+1;i++)
18         a[i]=0;
19     int x,y;
20     for(int i=1;i<=r;i++){
21         scanf("%d%d",&x,&y);
22         if(x>y) swap(x,y);//
23         if(vis[x][y])//判重
24             continue;
25         vis[x][y]=1;
26         b[x+1]--;//後面的減少
27         b[y]++;//前面的增加
28     }
29     for(int i=1;i<=n;i++){
30         a[i]=a[i-1]+b[i];
31         printf("%d ",a[i]);
32     }
33     return 0;
34 }
View Code

TLE掉的程式碼:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<cstdio>
 6 using namespace std;
 7 const int maxx=1e5+10;
 8 int main(){
 9     int n,ii,h,r;
10     cin>>n>>ii>>h>>r;
11     int a[maxx]={0};
12     for(int i=1;i<=n;i++){
13         a[i]=h;
14     }
15     for(int i=0;i<r;i++){
16         int num1,num2;
17         scanf("%d %d",&num1,&num2);
18         if(num1>num2){
19             swap(num1,num2);
20         }
21         for(int j=num1+1;j<num2;j++){
22             a[j]--;
23         }
24     }
25     for(int i=1;i<=n;i++){
26         printf("%d ",a[i]);
27     }
28 }
View Code