牛客网 小马哥的超级盐水 (双向枚举)

链接:https://www.nowcoder.com/acm/contest/94/K
来源:牛客网

分析:n的最大值能达到35,有2^35种状态,不能直接枚举所有的状态。

          但可以把n分成两个部分,这样每个部分的状态枚举就能在规定时间内达到。

          设i为第一个部分的状态,j为第二个部分的状态。

          则有(ai+aj)/(bi+bj)=x/y,进一步化为 ai*y-bi*x=bj*x-aj*y

          就可以在将每个第一部分的状态,通过二分找到第二部分中能与之匹配的状态

代码如下:

      

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN=40;
typedef long long LL;
int a[MAXN];
int b[MAXN];
int t,x,y,n,n1,n2,nowa,nowb;
LL ans;
int poi1[1000100],poi2[1000100];

int main()
{
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
       ans=0;
       int cnt1=1;
       int cnt2=1;
      cin>>n>>x>>y;
      for(int i=1;i<=n;i++)
          cin>>a[i]>>b[i];

      n1=n/2;
      for(int i=0;i<(1<<n1);i++)
      {
          nowa=0;
          nowb=0;
          for(int j=1;j<=n1;j++)
          {
           if(i&(1<<(j-1)))
           {
              nowa+=a[j];
              nowb+=b[j];
           }
          }
         poi1[cnt1]=nowa*y-nowb*x;
         cnt1++;
      }

      n2=n-n1;

        for(int i=0;i<(1<<n2);i++)
      {
          nowa=0;
          nowb=0;
          for(int j=1;j<=n2;j++)
          {
              int k=j+n1;
           if(i&(1<<(j-1)))
           {
              nowa+=a[k];
              nowb+=b[k];
           }
          }
        // cout<<cnt2<<" "<<nowa<<" "<<y<<" "<<nowb<<" "<<x<<endl;
         poi2[cnt2]=nowa*y-nowb*x;
         cnt2++;
      }
      sort(poi2+1,poi2+cnt2);
      
      for(int i=1;i<cnt1;i++)
      {
        int need=-poi1[i];
        ans+=upper_bound(poi2+1,poi2+cnt2,need)-lower_bound(poi2+1,poi2+cnt2,need);
      }
      cout<<ans-1<<endl;
    }
    return 0;
}

     

原文地址:https://www.cnblogs.com/a249189046/p/8877876.html