BZOJ4927第一题 双指针+DP
Posted yinwuxiao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ4927第一题 双指针+DP相关的知识,希望对你有一定的参考价值。
题解:
虽然是过了,不过做的十分智障
首先是有 2根 2 1 1 , 3根 1 1 1
这两种方法
然后考虑2 2 1 1
two-point-two没啥好说的
3 1 1 1
我很智障的以为数据范围是1e9
然后写了hash,刚开始还开错范围
把int换short int才卡过了空间
首先枚举 1 1 1
然后枚举3 中的一条边
既然1e7直接记录每个数能由两个数组成的方案数
另外再减去这条边参与的方案数(直接两个数减一下查有几个就好了)
然后细节还挺多的搞个对拍就可以了
#pragma G++ optimize (2) #include <bits/stdc++.h> using namespace std; #define N 6000 #define rg register #define IL inline #define ll long long int a[N],n; unsigned ll ans,ans3; #define js(x) x*(x-1)/2*(x-2)/3*(x-3)/4 const int mo1=1.3e7+7; const int NN=1.3e7+1e5; const int mo2=2.6e7+7; const int N2=2.6e7+1e5; int hash1[NN],hash2[NN],hash4[N2]; short int hash3[N2],hash5[N2]; char ss[1<<20],*A=ss,*B=ss; inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<20,stdin),A==B)?EOF:*A++;} template<class T>void read(T&x){ rg int f=1,c;while(c=gc(),c<48||57<c)if(c==‘-‘)f=-1;x=c^48; while(c=gc(),47<c&&c<58)x=(x<<3)+(x<<1)+(c^48);x*=f; } IL void push(int x) { int y=x%mo1; while (hash1[y]&&hash1[y]!=x) y++; hash1[y]=x; hash2[y]++; } IL int find1(int x) { int y=x%mo1; while (hash1[y]&&hash1[y]!=x) y++; if (hash1[y]==x) return(hash2[y]); else return(0); } IL void push2(int x,int y) { int z=(1ll*y*5000+x)%mo2; while (hash3[z]&&!(hash3[z]==x&&hash4[z]==y)) z++; hash3[z]=x; hash4[z]=y; hash5[z]++; } IL int find2(int x,int y) { int z=(1ll*y*5000+x)%mo2; while (hash3[z]&&!(hash3[z]==x&&hash4[z]==y)) z++; if (hash3[z]==x&&hash4[z]==y) return(hash5[z]); else return(0); } IL bool cmp(int a,int b) { return(a<b); } int now,cnt; #define INF 1e9 int main() { freopen("noi.in","r",stdin); freopen("noi.out","w",stdout); read(n); for (rg int i=1;i<=n;i++) read(a[i]); sort(a+1,a+n+1,cmp); for (rg int i=1;i<=n;i++) for (rg int j=i+1;j<=n;j++) push(a[i]+a[j]); a[0]=INF; for (rg int i=1;i<=n;i++) for (rg int j=i+1;j<=n;j++) push2(i,a[i]+a[j]),push2(j,a[i]+a[j]); now=0; while (++now<=n) { cnt=1; while (now<n&&a[now+1]==a[now]) cnt++,now++; if (cnt>=2) { int h=1,t=n; ll ans2=0; while (h<t) { int h1=h,t1=t; while (a[h]==a[h+1]&&h<t) h++; while (a[t]+a[h]>a[now]&&h<t) t--; if (a[t]+a[h]!=a[now]) { h++; continue; } t1=t; while (a[t]==a[t-1]&&h<t) t--; if (h==t) { int xx=t1-h1+1; if (t1-h1+1>=4) ans+=1ll*cnt*(cnt-1)/2*js(xx); ans+=1ll*ans2*cnt*(cnt-1)/2*(t1-h1+1)*(t1-h1)/2; break; } if (h-h1>=1&&t1-t>=1) { ans+=1ll*cnt*(cnt-1)/2*(h-h1)*(h-h1+1)/2*(t1-t)*(t1-t+1)/2; } ans+=1ll*cnt*(cnt-1)/2*ans2*(t1-t+1)*(h-h1+1); ans2+=(t1-t+1)*(h-h1+1); h++; } } if (cnt>=3) { rg ll ans2=1ll*cnt*(cnt-1)*(cnt-2)/6; unsigned rg ll ans4=0; for (rg int i=1;i<=n;i++) { if (a[now]>a[i]) { int x=find1(a[now]-a[i]); int y=find2(i,a[now]-a[i]); ans4+=1ll*(x-y)*ans2; } } ans3+=ans4/3; } } //ans3/=3; cout<<ans+ans3<<endl; return 0; }
对拍 n^6
#include <bits/stdc++.h> using namespace std; #define rg register #define N 10000 #define rep(i,x,y) for (rg int i=x;i<=y;i++) int b[10]; bool cmp(int x,int y) { return(x<y); } int a[N],n; bool pd1(int x1,int x2,int x3,int x4,int x5,int x6) { b[1]=a[x1],b[2]=a[x2],b[3]=a[x3],b[4]=a[x4],b[5]=a[x5],b[6]=a[x6]; sort(b+1,b+6+1,cmp); if (b[1]+b[4]==b[2]+b[3]&&b[2]+b[3]==b[5]&&b[5]==b[6]) return(1); else return(0); } bool pd2(int x1,int x2,int x3,int x4,int x5,int x6) { b[1]=a[x1],b[2]=a[x2],b[3]=a[x3],b[4]=a[x4],b[5]=a[x5],b[6]=a[x6]; sort(b+1,b+6+1,cmp); if (b[1]+b[2]+b[3]==b[4]&&b[4]==b[5]&&b[5]==b[6]) return(1); else return(0); } int main() { freopen("noi.in","r",stdin); freopen("noi2.out","w",stdout); std::ios::sync_with_stdio(false); cin>>n; for (int i=1;i<=n;i++) cin>>a[i]; int cnt=0,cnt2=0; rep(i1,1,n) rep(i2,i1+1,n) rep(i3,i2+1,n) rep(i4,i3+1,n) rep(i5,i4+1,n) rep(i6,i5+1,n) if (pd1(i1,i2,i3,i4,i5,i6)) { cnt++; } rep(i1,1,n) rep(i2,i1+1,n) rep(i3,i2+1,n) rep(i4,i3+1,n) rep(i5,i4+1,n) rep(i6,i5+1,n) if (pd2(i1,i2,i3,i4,i5,i6)) { // cout<<i1<<" "<<i2<<" "<<i3<<" "<<i4<<" "<<i5<<" "<<i6<<endl; cnt++; } cout<<cnt+cnt2<<endl; return 0; }
以上是关于BZOJ4927第一题 双指针+DP的主要内容,如果未能解决你的问题,请参考以下文章