2019 上海網絡賽 J stone name (01揹包)

題目:https://nanti.jisuanke.com/t/41420c++

題意:給你一個集合,而後讓你拆成兩個集合 x,y    求知足  x>y  &&  x-(x集合中最小值) <=y  的方案數spa

思路:首先咱們先拆分問題,咱們能不能求出集合不一樣值的方案數,這個很簡單,咱們dp[i],i表明當前重量的方案數,而後咱們很容易就能得知枚舉重量  推導式就是  dp[i]=dp[i]+dp[i-a[i]],如今咱們如何求出方案數咱們已經知道了,咱們怎麼獲得知足題目給的條件的方案數呢,咱們知道總共集合和是多少,咱們又知道當前重量是多少 ,咱們只要知道當前集合的最小值x是多少,  i>sum-i &&  (i-x)<= sum-i, 如今問題就在咱們如何肯定最小值,其實很簡單,咱們只要把物品從大到小排序,咱們就能肯定當前放的物品必定是當前最小,而後判斷便可code

 

#include<bits/stdc++.h>
#define maxn 305
#define mod 1000000007
using namespace std;
typedef long long ll;
int t,n;
int a[maxn];
int sum,num;
int vis[maxn];
int dp[150005];
void init(){
    scanf("%d",&n);
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        num+=a[i];
    }
}
int pan(int j,int x){
    if(j>=num-j&&j-x<=num-j) return 1;
    return 0;
}
int cmp(int x,int y){
    return x>y; 
}
int main(){
    scanf("%d",&t);
    while(t--){
        sum=0;num=0;
        init();
        sort(a+1,a+n+1,cmp);
        dp[0]=1;
        for(int i=1;i<=n;i++){
            for(int j=num;j>=a[i];j--){
                dp[j]=(dp[j]+dp[j-a[i]])%mod;
                if(pan(j,a[i])){
                    sum=(sum+dp[j-a[i]])%mod; 
                }
            }
        } 
        printf("%d\n",(sum+mod)%mod);
    }
} 
相關文章
相關標籤/搜索