Knapsack

题目背景

SOURCE:NOIP2016-RZZ-4 T2

题目描述

有 n 个物品,第 i 个物品的重量为 ai 。

设 f(i,j,k,l,m) 为满足以下约束的物品集合数量:

集合中所有物品的重量和恰好为 m 。

集合包含物品 i 和物品 j 。

集合不包含物品 k 和物品 l 。

给出一个正整数 s ,求:

答案对 10^9+7 取模。

输入格式

第一行,两个正整数 n,s 。

第二行,n 个正整数 ai,描述每个物品的重量。

输出格式

输出一行,一个整数表示答案对 10^9+7 取模后的结果。

样例数据 1

输入

4 4

1 2 3 4

输出

8

备注

【数据规模与约定】

对于 30% 的数据,n,s≤10。

对于另 20% 的数据,ai=1。

对于 80% 的数据,n,s≤100。

对于 100% 的数据,n,s≤1000。

考场上并没有看出来是一道背包,然后写了30" role="presentation" style="position: relative;">3030分的搜索和20" role="presentation" style="position: relative;">2020分的数学,结果数学的公式推错了233,30" role="presentation" style="position: relative;">3030分滚粗 。

刚刚已经说了,正解是背包。这道题最烦的就是i,j,k,l" role="presentation" style="position: relative;">i,j,k,li,j,k,l的限制条件,如果这个处理好了就没什么问题了。好吧其实限制条件很好办。

多加四维来表示i,j,k,l" role="presentation" style="position: relative;">i,j,k,li,j,k,l的状态?可以,但想想码量真是可怕。

于是我们将四维压成二维,用二维表示必须选的和必须不选的选取数量,然后背包就做完了。

等等,好像还有点问题,这样子过不了样例啊?

好吧这道题说的数对是有序数对,答案还要乘四。

30" role="presentation" style="position: relative;">3030分代码:

#include<bits/stdc++.h>
#define mod 1000000007
#define ll long long
#define N 1005
using namespace std;
inline ll read(){
    ll ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
    return ans;
}
ll n,s,a[1005],ans,cnt[10000];
inline void dfs(ll pos,ll c1,ll c2,ll sum,ll now){
    if(sum>s)return;
    if(pos==n+1){
        if(c1>=2&&c2>=2&&sum)++cnt[now];
        return;
    }
    dfs(pos+1,c1,c2+1,sum+a[pos],now+(1<<(pos-1)));
    dfs(pos+1,c1+1,c2,sum,now);
}
inline ll sol(ll x){
    ll tot[2]={0};
    while(x){
        ++tot[x&1];
        x>>=1;
    }
    tot[0]=n-tot[1];
    return (tot[0]*(tot[0]-1)>>1)%mod*(tot[1]*(tot[1]-1)>>1%mod)%mod;
}
int main(){
//  freopen("knapsack.in","r",stdin);
//  freopen("knapsack.out","w",stdout);
    ans=0,n=read(),s=read();
    for(ll i=1;i<=n;++i)a[i]=read();
    sort(a+1,a+n+1);
    dfs(1ll,0ll,0ll,0ll,0ll);
    for(ll i=1;i<=(1<<n);++i)if(cnt[i])ans+=sol(i),ans%=mod;
    printf("%lld",ans<<2%mod);
    return 0;
}

满分代码(滚动数组优化):

#include<bits/stdc++.h>
#define mod 1000000007
#define S 2005
#define ll long long
using namespace std;
inline ll read(){
    ll ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
    return ans;
}
ll n,s,f[S][3][3],g[S][3][3],ans=0;
int main(){
    n=read(),s=read();
    f[0][0][0]=g[0][0][0]=1;
    for(int i=1;i<=n;++i){
        ll x=read();
        for(int j=0;j<=s;++j){
            for(int k=0;k<=2;++k)
                for(int l=0;l<=2;++l){
                    if(!f[j][k][l])continue;
                    if(j<=s-x){
                        g[j+x][k][l]=g[j+x][k][l]+f[j][k][l];
                        if(g[j+x][k][l]>=mod)g[j+x][k][l]-=mod;
                        if(k!=2){
                            g[j+x][k+1][l]=g[j+x][k+1][l]+f[j][k][l];
                            if(g[j+x][k+1][l]>=mod)g[j+x][k+1][l]-=mod;
                        }
                    }
                    if(l!=2){
                        g[j][k][l+1]=g[j][k][l+1]+f[j][k][l];
                        if(g[j][k][l+1]>=mod)g[j][k][l+1]-=mod;
                    }
                }
        }
        for(int j=0;j<=s;++j)
            for(int k=0;k<=2;++k)
                for(int l=0;l<=2;++l)
                    f[j][k][l]=g[j][k][l];
    }
    for(int i=1;i<=s;++i){
        ans+=f[i][2][2];
        if(ans>=mod)ans-=mod;
    }
    printf("%lld",(ans<<2)%mod);
    return 0;
}

2018.07.10NOIP模拟 Knapsack(单调队列优化dp)的更多相关文章

  1. 2018.09.26洛谷P3957 跳房子(二分+单调队列优化dp)

    传送门 表示去年考普及组的时候失了智,现在看来并不是很难啊. 直接二分答案然后单调队列优化dp检验就行了. 注意入队和出队的条件. 代码: #include<bits/stdc++.h> ...

  2. 2018.09.23 孙悟空大战鲤鱼精(单调队列优化dp)

    描述 孙悟空大战鲤鱼精,孙悟空在通天河遇到鲤鱼精,他嫉恶如仇,看见妖精就手痒(忘了自己是妖精).但是鲤鱼精知道孙悟空的厉害,在孙悟空来到通天河,鲤鱼精就跑到了河对面.于是孙悟空就去追鲤鱼精. 我们可以 ...

  3. 2018.09.10 bzoj1499: [NOI2005]瑰丽华尔兹(单调队列优化dp)

    传送门 单调队列优化dp好题. 这题其实很简单. 我们很容易想到一个O(T∗n∗m)" role="presentation" style="position: ...

  4. 2018.09.10 bzoj1855: [Scoi2010]股票交易(单调队列优化dp)

    传送门 单调队列优化dp好题. 有一个很明显的状态设置是f[i][j]表示前i天完剩下了j分股票的最优值. 显然f[i][j]可以从f[i-w-1][k]转移过来. 方程很好推啊. 对于j<kj ...

  5. 2018.09.06 烽火传递(单调队列优化dp)

    描述 烽火台是重要的军事防御设施,一般建在交通要道或险要处.一旦有军情发生,则白天用浓烟,晚上有火光传递军情. 在某两个城市之间有 n 座烽火台,每个烽火台发出信号都有一定的代价.为了使情报准确传递, ...

  6. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  7. 单调队列以及单调队列优化DP

    单调队列定义: 其实单调队列就是一种队列内的元素有单调性的队列,因为其单调性所以经常会被用来维护区间最值或者降低DP的维数已达到降维来减少空间及时间的目的. 单调队列的一般应用: 1.维护区间最值 2 ...

  8. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  9. hdu3401:单调队列优化dp

    第一个单调队列优化dp 写了半天,最后初始化搞错了还一直wa.. 题目大意: 炒股,总共 t 天,每天可以买入na[i]股,卖出nb[i]股,价钱分别为pa[i]和pb[i],最大同时拥有p股 且一次 ...

随机推荐

  1. idea中spring boot启动后无法访问jsp

    出自:https://www.jianshu.com/p/470b28d76147 第一种: 打开File > Project Structure > Facetes 如图1: 图1 如果 ...

  2. 18 网络编程-TCP/IP各层介绍(5层模型讲解)

    1.TCP/IP五层协议讲解 物理层--数据链路层--网络层--传输层--应用层 我们将应用层,表示层,会话层并作应用层,从tcp/ip五层协议的角度来阐述每层的由来与功能,搞清楚了每层的主要协议 就 ...

  3. 7 python 类的组合

    1.组合与重用性 软件重用的重要方式除了继承之外还有另外一种方式,即:组合 组合指的是,在一个类中以另外一个类的对象作为 1.一个类的属性可以是一个类对象,通常情况下在一个类里面很少定义一个对象就是它 ...

  4. ArcGIS案例学习笔记3_1

    ArcGIS案例学习笔记3_1 联系方式:谢老师,135_4855_4328,xiexiaokui#139.com 时间:第三天上午 内容1:ArcGIS 平台介绍 体系结构 Arcgis for d ...

  5. hibernate中多对多的注解配置

    hibernate多对多的注解配置中的自动生成中间表的配置: @Entity@Table(name="test_student")public class Students { @ ...

  6. Group by 内部排序

    1.right join #  update_time  gid=>sid, group_status => s_table select a.* from comment as a ri ...

  7. chrome 调试参数大全

    一.鼠标事件监控: monitorEvents(document, ["scroll"]); monitorEvents($('#action-button'), ["m ...

  8. IDEA 码云 安装

    安装方式: 从IDEA插件仓库搜索Gitee下载并安装即可. 登陆并拉取项目代码 1. 启动 idea,选择Check out from Version Control-码云 2. 输入用户名和密码, ...

  9. Spring AsyncRestTemplate

    类说明 AsyncRestTemplate 是 Spring中提供异步的客户端HTTP访问的核心类.与RestTemplate类相似,它提供了一些类似的方法,只不过返回类型不是具体的结果,而是List ...

  10. 【校招面试 之 C/C++】第3题 为什么要内存对齐?以及内存对齐的方式

    1.为什么要进行内存对? 参考:https://blog.csdn.net/a369000753/article/details/51188915 所谓内存对齐,是为了让内存存取更有效率而采用的一种编 ...