9.16题解
这套题总的来说,由于出题人的数据非常水,所以我用各种方法水了过去
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 }