差分两道题

https://www.acwing.com/activity/content/problem/content/334/

参考代码:

 1 //差分的性质运用和基本思维
 2 //差分就不多说了基本操作
 3 //题目要求得到的数都一样的最小操作次数,我们在求出差分数组之后可以进行如下操作
 4 //因为我们最终目的是使得cf[2]~cf[N+1]都是0,a[1]=cf[1]
 5 //所以说第一步肯定是尽量中和差分数组中的正负数,这种的是2<=i,j<=n
 6 //第二种操作是修改a[i]的前缀,即i=1,2<=j<=n,就是让cf[1]+1,cf[j]-=1,那他只能让修改差分数组cf[j]一个数而已
 7 //第三种操作是修改a[i]的后缀,即2<=i<=n,j=n+1,同上,也只能修改cf[i]种的一个数而已
 8 //第四种是修改a[i]全部,即i=1,j=n+1这种没有操作意义所以说不要选这种操纵
 9 //因此,现在的核心想法就是如何运用上述的三种操作,可以更快用更少的操作取完成我们的目标。从直觉上看,我们应该多用第一种操作,
10 //因为第一种操作它一次可以改变差分数组的两个数,而第二、三种操作,它一次只能改变差分数组中的一个数。
11 //那就很明确了,正数和负数中和需要min(zs,fs)次,还剩下abs(zs-fs)次,剩下的这些既可以与cf[1]配对
12 //也可以与cf[n+1]配对,即执行操作二三来修改他们,因此总次数是min(zs,fs)+abs(zs-fs)=max(zs,fs)
13 //至于产生序列的种数,我们知道,修改后序列的种数很明显是由cf[1]决定的,还剩下的abs(zs-fs)中,既可以与cf[1]配对
14 //也可以与cf[n+1]配对,那么cf[1]就可以分配0,1,2.....abs(zs-fs)个,同理cf[n+1]可分配abs(zs-fs),......1,0个,即操作二我们会修改
15 //cf[1]的值,如果我们进行abs(zs-fs)+1个不同的序列次操作二,就会有abs(zs-fs)+1个不同的序列
16 //所以说综上所述要达到所有数都相等的总次数是min(zs,fs)+abs(zs-fs)=max(zs,fs)
17 //产生不同的序列的种数是abs(zs-fs)+1个
18 #include<bits/stdc++.h>
19 using namespace std;
20 #define int long long
21 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
22 const int N=1e5+10;
23 int a[N];
24 int n;
25 inline int read(){
26      int s=0,w=1;char ch=getchar();
27     while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
28     while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
29     return s*w;
30 }
31 inline void write(int x)
32 {
33     if (x < 0) putchar('-'), x = -x;
34     if(x > 9)
35         write(x / 10);
36     putchar(x % 10 + '0');
37     return;
38 }
39 signed main()
40 {
41     IOS;
42     n=read();
43     for(int i=1;i<=n;i++)
44     {
45         a[i]=read();
46         //a[i]-=a[i-1];
47         //cout<<a[i]<<" ";
48     }
49     //cout<<endl;
50     int zs=0;
51     int fs=0;
52     for(int i=2;i<=n;i++)
53     {
54         int t=a[i]-a[i-1];
55         if(t>0)
56         {
57             zs+=t;
58         }
59         else
60         {
61             fs-=t;
62         }
63     }
64     cout<<max(zs,fs)<<endl;
65     cout<<abs(zs-fs)+1<<endl;
66     return 0;
67 }

https://www.acwing.com/activity/content/problem/content/335/

参考代码:

 1 //差分优化和+区间的处理问题
 2 //m对关系其实表示的就是牛与牛之间的相对高度
 3 //我们设每对关系中的牛的身高是a,b(b>a),a与b能相互看见表示从下标ai+1到b-1的数都要--,因为ab两头牛
 4 //比他们中间其余的牛的身高都要高,其余牛的身高至少要比a,b小1
 5 //另外c[p]肯定是为0的
 6 //于是我们思路就确定了,但是很现实的是这里每对关系都相当于一个区间,如果直接对c数组操作的复杂度是o(nm)
 7 //看一下数据就知道会不会爆了
 8 //这里用差分数组来优化一下,区间的数都加上或者减去一个数表示对差分数组的操作(不说了)
 9 //最后求一下前缀和,用h+c[i]就是每头牛的身高了
10 //蓝书的题目真的是宝藏题目
11 #include<bits/stdc++.h>
12 using namespace std;
13 #define int long long
14 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
15 const int N=5e3+10;
16 int n,p,h,m;
17 int a[N];
18 int d[N];//差分数组
19 int c[N];//表示比最高的牛矮多少
20 map<pair<int,int>,int>s;
21 inline int read(){
22      int s=0,w=1;char ch=getchar();
23     while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
24     while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
25     return s*w;
26 }
27 inline void write(int x)
28 {
29     if (x < 0) putchar('-'), x = -x;
30     if(x > 9)
31         write(x / 10);
32     putchar(x % 10 + '0');
33     return;
34 }
35 signed main()
36 {
37     IOS;
38     n=read(),p=read(),h=read(),m=read();
39     int x,y;
40     for(int i=1;i<=m;i++)
41     {
42         x=read(),y=read();
43         if(x>y)
44         {
45             swap(x,y);
46         }
47         if(s[make_pair(x,y)])
48         continue;
49         d[y]++;
50         d[x+1]--;
51         s[make_pair(x,y)]=1;
52     }
53     for(int i=1;i<=n;i++)
54     {
55         c[i]=c[i-1]+d[i];
56         cout<<h+c[i]<<endl;
57     }
58     return 0;
59 }

 

posted @ 2023-01-11 20:19  江上舟摇  阅读(7)  评论(0编辑  收藏  举报