洛谷P1164 小A点菜(母函数)

洛谷P1164 小A点菜(母函数)

题目背景

uim神犇拿到了uoi的ra(镭牌)后,立刻拉着基友小A到了一家……餐馆,很低端的那种。
uim指着墙上的价目表(太低级了没有菜单),说:“随便点”。

题目描述

不过uim由于买了一些辅(e)辅(ro)书,口袋里只剩M元(M<=10000)。
餐馆虽低端,但是菜品种类不少,有N种(N<=100),第i种卖ai元(ai<=1000)。由于是很低端的餐馆,所以每种菜只有一份。
小A奉行“不把钱吃光不罢休”,所以他点单一定刚好吧uim身上所有钱花完。他想知道有多少种点菜方法。
由于小A肚子太饿,所以最多只能等待1秒。

输入输出格式

输入格式:

第一行是两个数字,表示N和M。
第二行起N个正数ai(可以有相同的数字,每个数字均在1000以内)。

输出格式:

一个正整数,表示点菜方案数。

输入输出样例

输入样例#1:

4 4
1 1 2 2

输出样例#1:

3

解题分析

用母函数求解。由于每一种菜只有一份,因此第i种菜的母函数为1+x^ai,将所有菜的母函数相乘,求得指数为m的系数即可。

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       

using namespace std;
int n, m; 
struct node{
	int e;
	int f;
	node *next;
	node():next(NULL){
	}
	void set(int e1, int f1){
		e = e1;
		f = f1;
	}
}; 

void add_item(node *now, int e, int f){
	node *tmp;
	while(now){
		if(now->next == NULL){
			tmp = new node;
			tmp->set(e, f);
			now->next = tmp;
			return;
		} else if(now->next->e == e){
			now->next->f += f;
			tmp = now->next;
			if(tmp->f==0){
				now->next = tmp->next;
				delete tmp;
			}
			return;
		} else if(now->next->e > e){
			tmp = new node;
			tmp->set(e, f);
			tmp->next = now->next;
			now->next = tmp;
			return;
		}
		now = now->next;
	} 		
}

void add_of_two(node *n1, node *n2){
	node *tmp = n1, *tmp1 = n1->next, *tmp2 = n2->next, *tmp3;
	while(tmp1!=NULL || tmp2!=NULL){
		if(tmp1!=NULL && tmp2!=NULL && tmp1->e == tmp2->e){
			tmp1->f += tmp2->f;
			if(tmp1->f == 0){
				tmp->next = tmp1->next;
				delete tmp1;
				tmp1 = tmp->next;				
			} else{
				tmp = tmp1;
				tmp1 = tmp1->next;
			}				
			tmp2 = tmp2->next;
		} else if(tmp2==NULL || tmp1!=NULL && tmp1->e < tmp2->e){
			tmp = tmp1;
			tmp1 = tmp1->next;
		} else if(tmp1==NULL || tmp2!=NULL && tmp1->e > tmp2->e){
			tmp3 = new node;
			tmp3->set(tmp2->e, tmp2->f);
			tmp3->next = tmp1;
			tmp->next = tmp3;
			tmp = tmp3;
			tmp2 = tmp2->next;
		}
	}
}

node * mul_item(node *n1, int e, int f){
	node *tmp = new node, *r = new node;
	n1 = n1->next;
	if(n1){
		tmp->set(n1->e + e, n1->f * f);
		tmp->next = NULL;
		r->next = tmp;
	}
	n1 = n1->next;
	while(n1){
		tmp->next = new node;
		tmp->next->set(n1->e + e, n1->f * f);
		tmp->next->next = NULL;
		tmp = tmp->next;
		if(n1->e+e > m)  // 优化 
			break;
		n1=n1->next;
		
	}
	return r;
}

void get_i(int &x){
	char ch = getchar();
	x = 0;
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)){
		x = x * 10 + ch - '0';
		ch = getchar();
	}
}

int main(){
	ios::sync_with_stdio(false);
	int i, p;
	node *h1 = new node, *h2 = new node;
	get_i(n), get_i(m);
	for(i=0; i
       
       
         next; while(h1){ if(h1->e == m){ cout< 
        
          f< 
         
           e>m){ cout<<0< 
          
            next; } return 0; } 
           
          
         
       
      
      
     
     
    
    
   
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值