noip2018 货币系统 题解
一、分析
看题目不难发现,这道题题意就是用一个尽可能含元素少的集合,把原集合里能拼出的数都拼出来,输出所含元素的数量。
众所周知,没有思路的时候看一眼数据范围,有时就恍然大悟。比如说这道题,\(a[i]\) 最大值才 \(25000\) ,\(n\) 最大也才 \(100\) .呵呵,直接暴力(正解的思路)
思路如下,我们把所有原数组能拼出来的数都枚举出来,因为乘法的本质都是加法,所以我们枚举只需要枚举原数组相加能拼出的数即可。如果存在拼出来的数属于原集合,就删去原集合中这个数(因为它可以被集合中的其他元素拼出,那它就没必要存在了)
具体实践代码中有详细解释
这里解释一下数组 \(sz[ ]\) 的含义
for(int i=y[1];i<=y[n];i++)
{
if(sz[i])
printf("%d ",i);//这里输出的就是元素个数为ans的新集合中的元素
}
#include<bits/stdc++.h>
#define maxn 26000
using namespace std;
int n,t,ans;
int y[105];
bool pd[maxn],sz[maxn];//这里定义了两个数组,pd是用来判断这个数i能否被拼出来的,sz[]往后看就明白了
int main()
{
scanf("%d",&t);
while(t--)
{
memset(sz,0,sizeof(sz));
memset(pd,0,sizeof(pd));//每次循环都要清零两个数组
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&y[i]);
pd[y[i]]=1;//原数组的元素一定能拼出(废话)
sz[y[i]]=1;//先把原数组中的元素都标为1,(把新集合的元素初始化为原集合的元素)
}
int ans=n;
sort(y+1,y+n+1);
for(int i=y[1];i<=y[n];i++)
{
if(pd[i])//原集合中出现了这个元素
{
for(int j=1;j<=n;j++)//把原集合里所有的元素都枚举一遍,为了相加拼出新元素
{
if(i+y[j]<=y[n])//为了节省空间的一步,仔细想想
{
pd[i+y[j]]=1;//能拼出这个元素
if(sz[i+y[j]])//如果原数组中存在这个新拼出数,那就在sz中删去(标为0)
{
sz[i+y[j]]=0;
ans--;//sz中元素就减少1;
}
}
}
}
}
printf("%d\n",ans);
}
return 0;
}
炫耀一下刚学的欧拉函数(大雾
\[\varphi(x) = x\prod \frac {p_i - 1}{p_i}
\]

浙公网安备 33010602011771号