1. 程式人生 > >小馬哥的超級鹽水 (牛客網景馳科技杯)

小馬哥的超級鹽水 (牛客網景馳科技杯)

連結:https://www.nowcoder.com/acm/contest/94/K

來源:牛客網

題意:給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)。所以列舉前面的然後找後面的就行了。

#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;
}