没 有 原 题 链 接
题目描述
题解
这是一个物品数不超过5、物品质量不超过10的计算完全背包方案数的问题,要求一个最小的背包大小,使得装满背包的方案数 ≥ h i \ge h_i ≥hi。
考虑到背包大小可能很大,我们可以用矩阵加速这个背包DP。设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示考虑前
i
i
i 个物品、背包大小为
j
j
j 的方案数,则
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
]
[
j
−
a
i
]
dp[i][j]=dp[i-1][j]+dp[i][j-a_i]
dp[i][j]=dp[i−1][j]+dp[i][j−ai]我们只保留有用的最大的10个
j
j
j,这样总状态数不超过 50,直接对这个DP矩阵加速即可。
然而这个 d p [ i ] [ j ] dp[i][j] dp[i][j] 貌似关于 j j j 并没有单调性?但是由于 a i ≤ 10 a_i\le 10 ai≤10,所以每连续10个 j j j 的DP值中的最大值是满足单调不降的,我们只需要通过这个二分找出包含答案的10的连续段即可。
通过预处理+把二分换成倍增,可以做到 O ( n 3 a 3 log h + q n 2 a 2 log h ) O(n^3a^3\log h+qn^2a^2\log h) O(n3a3logh+qn2a2logh) 的时间复杂度。
代码
#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define lll __int128
#define uns unsigned
#define IF (it->first)
#define IS (it->second)
#define END putchar('\n')
using namespace std;
const int MAXN=-1;
const ll INF=2e17;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
return f?x:-x;
}
int ptf[50],lpt;
inline void print(ll x,char c='\n'){
if(x<0)putchar('-'),x=-x;
ptf[lpt=1]=x%10;
while(x>9)x/=10,ptf[++lpt]=x%10;
while(lpt)putchar(ptf[lpt--]^48);
if(c>0)putchar(c);
}
inline ll lowbit(ll x){return x&-x;}
const int M=55;
const lll E=1;
struct matrix{
ll c[M][M];int n,m;matrix(){}
matrix(int N,int M){memset(c,0,sizeof(c)),n=N,m=M;}
inline matrix operator*(const matrix&b)const{
matrix res=matrix(n,b.m);
for(int i=0;i<n;i++)
for(int k=0;k<m;k++)if(c[i][k])
for(int j=0;j<b.m;j++)if(res.c[i][j]<INF){
lll ad=min(E*c[i][k]*b.c[k][j],E*INF);
res.c[i][j]+=ad;
if(res.c[i][j]>INF)res.c[i][j]=INF;
}
return res;
}
}A,B;
matrix mb[M+10];
int n,a[10],id[10][15],m;
signed main()
{
freopen("dignity.in","r",stdin);
freopen("dignity.out","w",stdout);
n=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)
for(int j=0;j<10;j++)id[i][j]=m++;
A=matrix(1,m),B=matrix(m,m);
for(int i=1;i<=n;i++){
for(int j=0;j<9;j++)
B.c[id[i][j+1]][id[i][j]]=1;
if(i>1){
for(int j=0;j<m;j++)
B.c[j][id[i][9]]=B.c[j][id[i-1][9]];
}B.c[id[i][10-a[i]]][id[i][9]]=1;
}
for(int i=1;i<=n;i++)A.c[0][id[i][9]]=1;
mb[0]=B;
for(int i=1;i<=60;i++)mb[i]=mb[i-1]*mb[i-1];
for(int Q=read();Q--;){
ll h=read(),t=0,lim=h*100+9;
matrix a=A;
for(int i=60;i>=0;i--)if(t+(1ll<<i)<=lim){
matrix ta=a*mb[i];
ll mx=0;
for(int i=0;i<10;i++)
mx=max(mx,ta.c[0][id[n][i]]);
if(mx<h)t+=(1ll<<i),a=ta;
}
if(h>1)t++,a=a*mb[0];
ll as=t-9;
for(int i=0;i<10;i++,as++)
if(a.c[0][id[n][i]]>=h)break;
if(as>h*100)printf("What a pity!\n");
else print(as);
}
return 0;
}