Rikka with Subset
题解:
如果 Bi 是 B 数组中除了 B0 以外第一个值不为 00的位置,那么显然 ii 就是 AA 中的最小数。
现在需要求出删掉 i后的B数组,过程大概是反向的背包,即从小到大让 b[j]-=b[j-i]。(类似筛法的思想) (这里顺序推过去的时候,我们把j-i看做一个组,当i要消去之后,对j的影响,不就是j-i存在的次数么
(当然和为(j-i)的情况要把包含i的情况处理掉不然会有重复计算,顺推就好了))。
时间复杂度 O(nm)。
注意对0这个点特殊处理一下。
比赛的时候想到实现不了,再次抱大佬大腿。。。
ac代码:
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; ll a[60]; ll b[10001]; int n,m; int main() { int t; cin>>t; while(t--) { scanf("%d %d",&n,&m); for(int i=0;i<=m;i++) scanf("%lld",&b[i]); int cnt=0; b[0]--; int flag=0; while(1) { ll i; flag=0; for(i=0;i<=m;i++) { if( b[i] > 0) { // cout<<i<<' '<<endl; if(i==0) { for(int j=0;j<b[i];j++) a[cnt++]=0; } else a[cnt++]=i; if( i!=0 ) b[i]--; break; } } if(i==0) { for(ll j=1;j<=m;j++) { if(b[j] >= b[0]) b[j] -= b[0]; } b[0]=0; // for(ll j=1;j<=m;j++) cout<<b[j]<<' '; // cout<<endl; } else for(ll j=i;j<=m;j++) b[j] -= b[j-i]; if(cnt==n) break; } cout<<a[0]; for(int i=1;i<n;i++) printf(" %lld",a[i]); cout<<endl; } return 0; }