前言:
第一篇题解,寫點自己在網上搜到的東西,雖然沒什麼卵用......
不會排版還要慢慢學......
作為一個菜雞可能以後發的大多是歌曲推薦(???或者是奇奇怪怪的東西(???
題目其實在hdu 1709,有多組數據
題面:
小C为了试验小X,便为物竞的小X出了一道物理相关的题:现在给出n个质量的砝码,问小X能称出多少种质量的物品,可是总有好事者想要破坏,于是乎,n达到了500,远远超出了小X能够承受的范围,锲而不舍的他决定寻求你们的帮助。
30%:n <=10
60%: n<=100
100%: n<=500 数据保证砝码的质量之和不超过20000
樣例輸入: 樣例輸出:
3 13
1
3
9
注意:天平有两边,两边均可放。
一、01背包
狀態轉移方程:f[ j ]=f[ j-a[ i ] ]或f[ j+a[ i ] ]
至於減法只要減一下取個絕對值就可以了
手測了一點點樣例,應該沒問題,要是有錯我再改
2019-03-02 17:43:36 AC
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int n,a[505],sum; int f[20005]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]),sum+=a[i]; } f[0]=1; for(int i=1;i<=n;i++){ for(int j=1;j<=sum;j++) if(f[j+a[i]]) f[j]=1; for(int j=sum;j>=1;j--) if(f[(int)abs(j-a[i])]) f[j]=1; } int ans=0; for(int i=1;i<=sum;i++)ans+=f[i]; printf("%d",ans); return 0; }
2019-03-01 00:24:50
二、普通母函數
自己在網上看的博客,就是整理一下,寫一些我覺得比較重要的
原文:https://blog.csdn.net/yu121380/article/details/79914529
例題:有1克、2克、3克、4克的砝码各一 枚,能称出哪几种重量?每种重量各有几种可能方案?
我們先在1g和2g間枚舉:(以下為引用)
(使用1g || 不使用1g)&&(使用2g || 不使用2g)
=使用1g&&使用2g || 不使用1g&&使用2g || 使用1g&&不使用2g || 不使用1g&&不使用2g
每个用 “||”分开的一项都是一种方案。“&&”表示选择第一项的情况下有选择了第二项。
大家可以发现这个表达式和一种表达式很像,没错,如果把“||”看成加法,“&&”看成乘法,和多项式的乘法一模一样。那么我们直觉的想到,有没有可能用多项式乘法来表示组合的情况呢?
我们再来看题目,题目需要的是几种砝码组合后的重量,是一个加法关系,但是在上式中“&&”是一种类似于乘法的运算关系,这怎么办呢?
有没有什么这样一种运算关系,以乘法的形式运算,但是结果表现出类似于加法的关系呢?正好有一个,那就是幂运算。Xm 乘上Xn结果是Xm+n,他完美的符合了我们的要求。那么以次数表示砝码的质量, 就可以以多项式的形式表示砝码组合的所有方案。
还是以前两个砝码为例说明,表示1g砝码的两种状态的多项式就是(x0+x1),表示2g的就是(x0+x2),x0表示没有使用砝码,所以重量为0,当然了因为x0 =1,所以也可以写成1,后面为了方便我会这么写。注意,砝码的质量是以次数表示的,而不是直觉上的用下标表示为x1,x2。这点很重要,不然的话就无法表现出幂运算的关系了。
(x0+x1)*(x0+x2)
=x0*x0 + x1*x0 + x0*x2 + x1*x2
=x0 + x1 + x2 + x3
很显然,有四种方案,0g、1g、2g、3g,结果与我们穷举的结果相同,而如果结果中有相同的项,那么合并同类项后每一项的系数就是这种重量有几种实现方案,这会在我们用此方法解决4个砝码问题的时候得到证明。那么接下来试试用这种表达式表示4个砝码的组合情况
(x0+x1)* (x0+x2) * (x0+x3)* (x0+x4)
=x0 + x1 + x2 + 2x3 + 2x4 + 2x5 + 2x6 + 2x7 + x8+ x9 + x10
解釋的非常清楚了,關於這道題的不同點是左右都能放砝碼,考慮減小的情況
所以這道題转化为(1+x^a[1])*(1+x^a[2])*(1+x^a[3])……(1+x^a[n])
接下來代碼,細節注釋在代碼里
然而代碼仍然是抄的,因為還不太理解,反正先發出來就是了
2019-03-02 17:43:36 AC
#include<iostream> #include<cstdio> using namespace std; int n,a[505],sum,ans;//sum为所有砝码的和也就是上界 int sup[20005],temp[20005]; //sup为當前運算后的結果(被乘多項式),存的是多项式的系数 //下标為多項式的次數,也就是砝码的重量 int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum+=a[i]; for(int i=0;i<=a[1];i+=a[1])sup[i]=1; //初始化第一個多項式,也就是用a[1]的多項式 for(int i=2;i<=n;i++){//生成后续的第i个多项式 for(int j=0;j<=sum;j++)//遍历当前结果多项式的第j項,與第i個多項式相乘 for(int k=0;j+k<=sum && k<=a[i];k+=a[i]){//遍歷第i個多項式的每一項 if(k>=j) temp[k-j]+=sup[j]; else temp[j-k]+=sup[j]; temp[j+k]+=sup[j]; } for(int j=0;j<=sum;j++){//將臨時的結果覆蓋當前結果,同時初始化temp sup[j]=temp[j]; temp[j]=0; } } for(int i=1;i<=sum;i++) if(sup[i]!=0)ans++;//如果這一項係數為0,代表不能拼成 printf("%d",ans); }
寫博客有點耗時間啊,以後還是有把握了再發博客吧,或者不務正業什麼的
2019-03-01 19:57:54