1. 程式人生 > >吃東西

吃東西

first break auto scan 暴力 其中 cst lin bar

吃東西

Time Limit:2000ms Memory Limit:1024MB

題目描述

一個神秘的村莊裏有4家美食店。這四家店分別有A,B,C,D種不同的美食。LYK想在每一家店都吃其中一種美食。每種美食需要吃的時間可能是不一樣的。

現在給定第1家店A種不同的美食所需要吃的時間a1,a2,…,aA。

給定第2家店B種不同的美食所需要吃的時間b1,b2,…,bB。

以及c和d。

LYK擁有n個時間,問它有幾種吃的方案。

輸入格式

第一行5個數分別表示n,A,B,C,D。

第二行A個數分別表示ai。

第三行B個數分別表示bi。

第四行C個數分別表示ci。

第五行D個數分別表示di。

輸出格式

一個數表示答案。

輸入樣例

11 3 1 1 1

4 5 6

3

2

1

輸出樣例

2

對於30%的數據A,B,C,D<=50

對於另外30%的數據n<=1000。

對於100%的數據1<=n<=100000000,1<=A,B,C,D<=5000,0<=ai,bi,ci,di<=100000000。

題解

暴力A*B求出A和B組合的所有方案。

暴力C*D求出C和D組合的所有方案。

再把AB和CD的方案組合。

n太大,不能用sort排序。

因為空間足夠大,可以按數值存一個數組,再O(n)從小到大放進去。

因為具有單調性,可以O(n)算出方案數。

代碼

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;
const int N=100000005,M=5005; 
int A,B,C,D,n,maxn,cntab,cntcd,now;
int a[M],b[M],c[M],d[M];
int f[N],ab[M*M],cd[M*M];
LL ans;
int main(){
    scanf("%d%d%d%d%d",&n,&A,&B,&C,&D);
    for(int i=1;i<=A;i++)scanf("%d",&a[i]);
    for(int i=1;i<=B;i++)scanf("%d",&b[i]);
    for(int i=1;i<=A;i++)
        for(int j=1;j<=B;j++)
            if(a[i]+b[j]<=n){
                f[a[i]+b[j]]++;
                maxn=max(maxn,a[i]+b[j]);
            }
    for(int i=0;i<=maxn;i++)
    	while(f[i]){
            f[i]--;
            ab[++cntab]=i;
        }
    for(int i=1;i<=C;i++)scanf("%d",&c[i]);
    for(int i=1;i<=D;i++)scanf("%d",&d[i]);
    maxn=0;
    for(int i=1;i<=C;i++)
        for(int j=1;j<=D;j++)
            if(c[i]+d[j]<=n){
                f[c[i]+d[j]]++;
                maxn=max(maxn,c[i]+d[j]);
            }
    for(int i=0;i<=maxn;i++)
    	while(f[i]){
            f[i]--;
            cd[++cntcd]=i;
        }
    for(int i=cntcd;i>=1;i--)
		if(ab[1]+cd[i]<=n){
			now=i;
    		break;
		}
    for(int i=1;i<=cntab;i++){
        ans+=now;
        while(now&&ab[i+1]+cd[now]>n)now--;
    }
    printf("%lld\n",ans);
    return 0;
}

吃東西