2023大厂真题提交网址(含题解):
www.CodeFun2000.com(http://101.43.147.120/)
最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
题目大意:
n n n个数里面选择 k k k个数出来,将他们累和。问有多少种数能被凑出来。(完全背包).
n , k ≤ 1000 n,k \leq 1000 n,k≤1000
题目思路:
母函数模板题。构造多项式 A ( x ) A(x) A(x),第 i i i项的系数 0 / 1 0/1 0/1代表是否有大小为 i i i的数.
然后 A k ( x ) A^k(x) Ak(x)的系数即为答案.
1.发现是一个幂次,可以用快速幂优化。但是注意点就是要额外维护变量代表当前两个多项式的项数最高次幂(也就是数组长度)。
2.由于只求[是否能够凑出],不求方案数。那么再fft求完后将res根据结果置为0/1.防止溢出。
复杂度: O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
template<class T>
void cc (T a[] , int n){
for (int i = 1 ; i <= n ; i++)
cout << a[i] << " ";
cout << endl;
}
namespace FFT{
const int maxn = 3e6+10;
const double Pi = acos(-1.0);
struct complex{
double x,y;
complex (double xx=0,double yy=0){x=xx,y=yy;}
}a[maxn],b[maxn];
complex operator + (complex a,complex b){ return complex(a.x+b.x , a.y+b.y);}
complex operator - (complex a,complex b){ return complex(a.x-b.x , a.y-b.y);}
complex operator * (complex a,complex b){ return complex(a.x*b.x-a.y*b.y , a.x*b.y+a.y*b.x);}//不懂的看复数的运算那部分
int l,r[maxn];
int limit = 1;
void fast_fast_tle(complex *A , int type)
{
for(int i=0;i<limit;i++)
if(i<r[i]) swap(A[i],A[r[i]]);//求出要迭代的序列
for(int mid=1;mid<limit;mid<<=1)//待合并区间的中点
{
complex Wn( cos(Pi/mid) , type*sin(Pi/mid) ); //单位根
for(int R=mid<<1,j=0;j<limit;j+=R)//R是区间的右端点,j表示前已经到哪个位置了
{
complex w(1,0);//幂
for(int k=0;k<mid;k++,w=w*Wn)//枚举左半部分
{
complex x=A[j+k],y=w*A[j+mid+k];//蝴蝶效应
A[j+k]=x+y;
A[j+mid+k]=x-y;
}
}
}
}
void ploy_mul (int x[] , int y[] , int n , int m , int res[])
{
// 多组数据记得清空. 要清空到lim
limit = 1;l = 0;
while(limit<=n+m) limit<<=1 , l++;
for (int i = 0 ; i <= limit ; i++)
a[i].x = a[i].y = b[i].x = b[i].y = 0.0 , r[i] = 0;
for (int i = 0 ; i < n ; i++) a[i].x = 1.0 * x[i] , a[i].y = 0.0;
for (int i = 0 ; i < m ; i++) b[i].x = 1.0 * y[i] , b[i].y = 0.0;
for(int i=0;i<limit;i++)
r[i]= ( r[i>>1]>>1 )| ( (i&1)<<(l-1) ) ;
fast_fast_tle(a,1);
fast_fast_tle(b,1);
for(int i=0;i<=limit;i++) a[i] = a[i] * b[i];
fast_fast_tle(a,-1);
for (int i = 0 ; i <= n + m ; i++) {
if ((int)(a[i].x/limit + 0.5))
res[i] = 1;
else
res[i] = 0;
}
}
}
int a[maxn];
int ploy_ksm (int a[] , int n , int b , int res[])
{
int len = 1;
res[0] = 1;
while (b){
if (b & 1)
FFT::ploy_mul(res , a , len , n , res) , len += n - 1;
b >>= 1;
FFT::ploy_mul(a , a , n , n , a);
n += n - 1;
}
return len;
}
int res[maxn];
int main()
{
ios::sync_with_stdio(false);
int n , m; cin >> n >> m;
int mx = 0;
for (int i = 1 ; i <= n ; i++){
int x; cin >> x;
a[x] = 1;
mx = max(mx, x);
}
int len = ploy_ksm(a , mx + 1 , m , res);
for (int i = 1 ; i < len ; i++)
if (res[i]) cout << i << " ";
cout << endl;
return 0;
}