这套题总的来说,由于出题人的数据非常水,所以我用各种方法水了过去
T1
暴搜+剪枝
剪枝一
如果$gcd$已经变成了1那么就没有继续走下去的必要,直接用最长序列长度尝试更新答案,然后直接$break$即可
剪枝二
如果你当前的$gcd$乘上最长的区间长度,对答案也不能作出贡献,那么你已经用了最长序列长度,且越往后走$gcd$会变的越小,那么答案永远不会变优,就也没有继续下去的必要了,$break$即可
然后就水过这道题

1 #include<iostream>
2 #include<cstdio>
3 #define maxn 100100
4 #define int long long
5 using namespace std;
6 int n,ans;
7 int a[maxn];
8 int gcd(int a,int b)
9 {
10 return b==0?a:gcd(b,a%b);
11 }
12 signed main()
13 {
14 //freopen("1.in","r",stdin);
15 scanf("%lld",&n);
16 for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
17 for(int i=1;i<=n;++i)
18 {
19 int GCD=a[i];
20 for(int j=i+1;j<=n;++j)
21 {
22 GCD=gcd(GCD,a[j]);
23 if(GCD*(n-i+1)<=ans) break;
24 if(GCD==1) {ans=max(ans,n-i+1); break;}
25 ans=max(ans,GCD*(j-i+1));
26 }
27 }
28 printf("%lld\n",ans);
29 return 0;
30 }
正解直接贴了

T2
考场上用假贪心水过去了,出题人的数据造的太水了,大家以各种姿势水过了这道题
这样就已经可以过了
1 #include<iostream>
2 #include<cstdio>
3 #define LL long long
4 using namespace std;
5 const int N=100010;
6 const LL inf=1e12;
7 int n,q;
8 LL ans;
9 LL a[N],b[N],ma1[N],ma2[N],mi1[N],mi2[N];
10 int read()
11 {
12 int s=0;char c=getchar();
13 while(c<'0'||c>'9') c=getchar();
14 while(c>='0'&&c<='9') {s=(s<<3)+(s<<1)+c-'0'; c=getchar();}
15 return s;
16 }
17 int main()
18 {
19 n=read();ans=inf;
20 for(int i=1;i<=n;i++) {a[i]=read();b[i]=read();}
21 mi1[0]=mi2[0]=inf;
22 for(int i=1;i<=n;i++){
23 LL x=min(a[i],b[i]); LL y=max(a[i],b[i]);
24 mi1[0]=min(mi1[0],x); ma1[0]=max(ma1[0],x);
25 mi2[0]=min(mi2[0],y); ma2[0]=max(ma2[0],y);
26 }
27 ans=(ma1[0]-mi1[0])*(ma2[0]-mi2[0]); printf("%lld\n",ans);
28 return 0;
29 }
我的贪心在$O(n^2)$的时候是没有问题的,但是他依旧会T,我就乱搞了一下,他就A了
我的贪心思路是枚举每一个小球,找到和它差值最小的n-1个球放进一堆
正解还是粘吧


1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 using namespace std;
5 #define ll long long
6 #define maxn 100010
7 #define inf 2000000000000000000
8 int n,ls1,ls2;
9 ll hzma1[maxn],hzmi1[maxn],qzma1[maxn],qzmi1[maxn];//x一列
10 ll hzma2[maxn],hzmi2[maxn],qzma2[maxn],qzmi2[maxn];//y一列
11 ll R,r=inf,B,b=inf,ans=inf;
12 struct node{
13 ll x,y;
14 }q[maxn];
15 int main()
16 {
17 scanf("%d",&n);
18 for(int i=1;i<=n;++i)
19 {
20 scanf("%lld%lld",&q[i].x,&q[i].y);
21 ls1=min(q[i].x,q[i].y); ls2=max(q[i].x,q[i].y);
22 q[i].x=ls1; q[i].y=ls2;
23 R=max(R,q[i].x); r=min(r,q[i].x);
24 B=max(B,q[i].y); b=min(b,q[i].y);
25 }
26 ans=(R-r)*(B-b); //cout<<ans<<endl;
27 memset(qzmi1,0x7f,sizeof(qzmi1)); memset(hzmi1,0x7f,sizeof(hzmi1));
28 memset(qzmi2,0x7f,sizeof(qzmi2)); memset(hzmi2,0x7f,sizeof(hzmi2));
29 for(int i=1;i<=n;++i)
30 {
31 qzmi1[i]=min(qzmi1[i-1],q[i].x);
32 qzma1[i]=max(qzma1[i-1],q[i].x);
33 qzmi2[i]=min(qzmi2[i-1],q[i].y);
34 qzma2[i]=max(qzma2[i-1],q[i].y);
35 }
36 for(int i=n;i>=1;--i)
37 {
38 hzmi1[i]=min(hzmi1[i+1],q[i].x);
39 hzma1[i]=max(hzma1[i+1],q[i].x);
40 hzmi2[i]=min(hzmi2[i+1],q[i].y);
41 hzma2[i]=max(hzma2[i+1],q[i].y);
42 }
43 for(int i=2;i<=n;++i)
44 {
45 if(qzmi2[i-1]<q[i].x) break;
46 R=max(qzma2[i-1],hzma1[i]); r=min(qzmi2[i-1],hzmi1[i]);
47 B=max(qzma1[i-1],hzma2[i]); b=min(qzmi1[i-1],hzmi2[i]);
48 ans=min(ans,(R-r)*(B-b));
49 }
50 printf("%lld",ans);
51 return 0;
52 }
T3
又是线段树优化DP,最近老是见到他,还是先考虑最简单的DP,设$f[i][j][k]$代表第$i$轮,两个指针分别在$j$和$k$的最小移动距离,转移的话让两个指针都分别动一下,设$p[i]$代表第$i$轮要在的位置,那么$f[i][p[i]][k]=min(f[i][p[i]][k],f[i-1][j][k]+abs(j-p[i]))$,$f[i][j][p[i]]=min(f[i][j][p[i]],f[i-1][j][k]+abs(k-p[i]))$,数组开不到把第一维滚起来就可以了,然而,这种$O(n^3)$的非常不优秀算法,依旧会得到$T0$的好成绩,考虑一下,除了滚动之外,我们是不是可以省掉后面两维中的某一维,我们会发现,除了初始状态之外,剩余所有状态,都有一个指针在$p[i]$的位置,所以有一维是和$i$直接相关的,我们可以省掉他,现在dp数组就变成了$f[i][j]$,代表第$i$轮,一个指针在$j$的位置上,另一个指针在$p[i]$的位置上的最小移动距离,转移的话一个是在上一轮在$p[i-1]$的位置上挪过来,另一种是不在$p[i-1]$的位置上挪过来,如果在$p[i-1]$的位置上挪过来那么$f[i][j]=min(f[i][j],f[i-1][j]+abs(p[i-1]-j))$,如果不在$p[i-1]$的位置上挪过来,那么$f[i][p[i-1]]=min(f[i][p[i-1]],f[i-1][j]+abs(j-p[i]))$,这样的话,转移就变成了$O(n^2)$的dp,依旧过不太去,考虑一下他的转移可以对应线段树中的区间加,区间最小值查询,单点修改,那么我们就把这个dp摁到线段树上去,由于我们有个$abs$的存在,所以线段树维护最小值,同时需要$f[i][j]-j$和$f[i][j]+j$,就都维护了,把$p[i]$和$j$的大小分情况,去线段树查询区间最小值即可

1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<cmath>
5 #define maxn 100100
6 #define int long long
7 #define inf 2000000000000000000
8 using namespace std;
9 struct node{
10 int zuo,you,w,lan,zxa/*+j*/,zxn/*-j*/;
11 }a[maxn<<2];
12 int n,q,A,B,ans=inf;
13 int p[maxn];
14 void up(int fa)
15 {
16 a[fa].w=min(a[2*fa].w,a[2*fa+1].w);
17 a[fa].zxa=min(a[2*fa].zxa,a[2*fa+1].zxa);
18 a[fa].zxn=min(a[2*fa].zxn,a[2*fa+1].zxn);
19 }
20 void down(int fa)
21 {
22 a[2*fa].w+=a[fa].lan; a[2*fa+1].w+=a[fa].lan;
23 a[2*fa].zxa+=a[fa].lan; a[2*fa+1].zxa+=a[fa].lan;
24 a[2*fa].zxn+=a[fa].lan; a[2*fa+1].zxn+=a[fa].lan;
25 a[2*fa].lan+=a[fa].lan; a[2*fa+1].lan+=a[fa].lan;
26 a[fa].lan=0;
27 }
28 void build(int fa,int l,int r)
29 {
30 a[fa].zuo=l; a[fa].you=r; a[fa].w=inf; a[fa].zxa=inf; a[fa].zxn=inf;
31 if(l==r)
32 {
33 if(l==A) {int ls=abs(p[1]-B); a[fa].w=min(a[fa].w,ls);}
34 if(l==B) {int ls=abs(p[1]-A); a[fa].w=min(a[fa].w,ls);}
35 a[fa].zxa=a[fa].w+a[fa].zuo; a[fa].zxn=a[fa].w-a[fa].zuo;
36 return ;
37 }
38 int mid=(l+r)>>1;
39 build(2*fa,l,mid); build(2*fa+1,mid+1,r); up(fa);
40 }
41 void add(int fa,int l,int r,int w)
42 {
43 if(a[fa].zuo>=l&&a[fa].you<=r)
44 {
45 a[fa].w+=w; a[fa].zxa+=w; a[fa].zxn+=w; a[fa].lan+=w;
46 return ;
47 }
48 if(a[fa].lan) down(fa);
49 int mid=(a[fa].zuo+a[fa].you)>>1;
50 if(l<=mid) add(2*fa,l,r,w);
51 if(r>mid) add(2*fa+1,l,r,w);
52 up(fa);
53 }
54 void change(int fa,int pos,int w)
55 {
56 if(a[fa].zuo==a[fa].you)
57 {
58 a[fa].w=w; a[fa].zxa=w+a[fa].zuo; a[fa].zxn=w-a[fa].zuo;
59 return ;
60 }
61 if(a[fa].lan) down(fa);
62 int mid=(a[fa].zuo+a[fa].you)>>1;
63 if(pos<=mid) change(2*fa,pos,w);
64 else change(2*fa+1,pos,w);
65 up(fa);
66 }
67 int query1(int fa,int l,int r)//-j
68 {
69 if(a[fa].zuo>=l&&a[fa].you<=r) return a[fa].zxn;
70 if(a[fa].lan) down(fa);
71 int mid=(a[fa].zuo+a[fa].you)>>1,minn=inf;
72 if(l<=mid) minn=min(minn,query1(2*fa,l,r));
73 if(r>mid) minn=min(minn,query1(2*fa+1,l,r));
74 return minn;
75 }
76 int query2(int fa,int l,int r)//+j
77 {
78 if(a[fa].zuo>=l&&a[fa].you<=r) return a[fa].zxa;
79 down(fa);
80 int mid=(a[fa].zuo+a[fa].you)>>1,minn=inf;
81 if(l<=mid) minn=min(minn,query2(2*fa,l,r));
82 if(r>mid) minn=min(minn,query2(2*fa+1,l,r));
83 return minn;
84 }
85 void upp(int fa)
86 {
87 if(a[fa].zuo==a[fa].you) return ;
88 down(fa); upp(2*fa); upp(2*fa+1); up(fa);
89 }
90 signed main()
91 {
92 //freopen("3.in","r",stdin);
93 //freopen("W.out","w",stdout);
94 scanf("%lld%lld%lld%lld",&n,&q,&A,&B);
95 for(int i=1;i<=q;++i) scanf("%lld",&p[i]);
96 build(1,1,n);
97 for(int i=2;i<=q;++i)
98 {
99 int minn=query1(1,1,p[i])+p[i];
100 minn=min(minn,query2(1,p[i]+1,n)-p[i]);
101 add(1,1,n,abs(p[i]-p[i-1])); change(1,p[i-1],minn);
102 }
103 upp(1); printf("%lld\n",a[1].w);
104 return 0;
105 }
