链接:https://ac.nowcoder.com/acm/contest/4911
B.三角形
给定n个盒子,每个盒子中有一定数量的宝物,现在你每次可以从一个盒子中拿取一个宝物,这样就会有很多种不同的价值和结果。现在问你前k小的价值结果的和是多少?
n<=100,k<=10000,假设盒子中最多宝物数量为m,保证k<=n*m<=10000。宝物价值不超过100.
首先这个题容易被数据范围误导,虽然每个盒子中最多可能有m<=100个物品,但是你最多从盒子中拿走一个物品,也就是说最后的结果sum<=n*100的,最大就是10000。这样分析一下数据范围,就可以想到方案数背包了(因为k最多也就10000),dp(i,sum)表示前i个盒子中拿物品,和为sum的方案数,这样复杂度为O(n * m * sum),最大为1e8左右。
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
const int maxn=10000+10;
int dp[101][maxn];
int mp[101][101];
signed main(){
int n,m;
scanf("%lld%lld",&n,&m);
int sum=0;
for(int i=1;i<=n;i++){
scanf("%lld",&mp[i][0]);
int maxx=0;
for(int j=1;j<=mp[i][0];j++){
scanf("%lld",&mp[i][j]);
maxx=max(maxx,mp[i][j]);
}
sum+=maxx;
}
//printf("sum %lld\n",sum);
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=mp[i][0];j++){
for(int k=sum;k>=mp[i][j];k--){
if(dp[i-1][k-mp[i][j]]){
dp[i][k]+=dp[i-1][k-mp[i][j]];
}
}
}
}
int cnt=0;
int res=0;
//printf("debug %lld\n",dp[n][1]);
for(int i=1;i<=sum;i++){
while(dp[n][i]){
cnt++;
res+=i;
dp[n][i]--;
if(cnt==m){
return printf("%lld\n",res),0;
}
}
}
return 0;
}
D:多元组
定义一个k元组为
现在给定一个数列,问你数列中最多有多少个k元组?对1e9+7取模
n<=1e5,k<=50.
首先思考一个经典的问题:逆序对问题。逆序对问题是k=2时的特殊情况,当n<=1e5时逆序对可以用树状数组快速求解。那么我们如何从二元组推三元组的情况呢?对于一个数a[i],他能组成三元组的情况,一定可以从在他之前,且值比他小的二元组的情况推导过来。
所以,令dp(i,j)表示前i个元素中,组成j元组的情况的个数,那么递推式就很明显了
递推式出来了,但是很明显直接算是O(n^2)的复杂度,所以我们需要借助树状数组快速计算。
具体来说,为每个元组k,开一颗树状数组,最多也就50颗树状数组这样,然后我们计算完dp(i,j)之后将其插入到对应的树状数组c(a[i],j)这个位置即可。
#include
#include
#include
#include
#include
#include
#include
#include
#define int long long
using namespace std;
const int maxn=1e5+10;
int c[maxn][51];
int f[maxn][51];
const int mod=1e9+7;
int a[maxn];
int lowbit(int x){
return x&-x;
}
vectorv;
int n,m;
int getid(int cur){
return lower_bound(v.begin(),v.end(),cur)-v.begin()+1;
}
void add(int x,int v,int y){
while(x<=n){
c[x][y]+=v;
x+=lowbit(x);
}
}
int query(int x,int y){
int res=0;
while(x>0){
(res+=c[x][y])%=mod;
x-=lowbit(x);
}
return res;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
v.push_back(a[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++){
a[i]=getid(a[i]);
}
for(int i=1;i<=n;i++){
add(a[i],1,1);
for(int j=2;j<=m;j++){
f[i][j]+=query(a[i]-1,j-1);
f[i][j]%=mod;
}
for(int j=2;j<=m;j++){
add(a[i],f[i][j],j);
}
}
printf("%lld\n",query(n,m));
return 0;
}