小马哥的超级盐水
题意:给n杯盐水,每一杯水有a单位盐,b单位水。给你一个x和y,问有多少种方法能配成x比y的盐水。
因为n只有35,没法枚举全部情况,如果n只有一般大,那么我们可以枚举所有情况。
我们可以把n分为两部分,枚举一部分的所有情况,然后找是否能和另一部分构成解。
对于(a1,b1)和(a2,b2)这两个集合。
易得(a1+a2)/(b1+b2)=x/y。
化简得到(y*a1-x*b1)=(x*b2-y*a2)。所以枚举前面的然后找后面的就行了。
AC代码:
#include <iostream> #include <string.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; struct node{ ll ai,bi; }a[105]; ll b[1<<19]; int main() { int t;cin>>t; while(t--) { ll n; ll x,y;cin>>n>>x>>y; for(int i=0;i<n;i++) { cin>>a[i].ai>>a[i].bi; } int p=0; ll n1=n/2; ll n2=n-n1; ll m1=(1<<n1); ll m2=(1<<n2); for(int i=0;i<(m2);i++) { ll sum=0; for(int j=0;j<n2;j++) { if((i>>j)&1) { sum+=a[j+n1].bi*x-a[j+n1].ai*y; } } b[p++]=sum; //cout<<ans-1<<endl; } sort(b,b+p); ll ans=0; for(int i=0;i<m1;i++) { ll sum=0; for(int j=0;j<n1;j++) { if((i>>j)&1) { sum+=a[j].ai*y-a[j].bi*x; } } ans+=upper_bound(b,b+p,sum)-lower_bound(b,b+p,sum); } cout<<ans-1<<endl; } return 0; }