一道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 Ball  http://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 Cow  http://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

 

posted @ 2020-12-06 15:25  bonel  阅读(113)  评论(0编辑  收藏  举报