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的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 4927: 第一题

算法入门双指针(中等 - 第一题)LeetCode 3

bzoj1044

[HAOI2008] 木棍分割 - dp,前缀和,双指针

双指针:盛最多水的容器(4.18leetcode每日一题)

LeetCode每日一题