• C++-蓝桥杯-波动数组[2014真题][DP优化]


    无非是计算s1个+a和s2个-b的排列数(s1+s2=(1+n)*n/2=sum)

    比如在第一位+a的话,之后的每个数都累积了+a,相当于当前排上了n-1个+a

    所以,可以设状态f[i][j]为:用数字1~i(每个只能选一次)可以组成和为j的方案数

    实际上就是一个容量=价值的01背包

    对于s1(0~sum):s=nx+s1*a-s2*b

    即依次验证,对于每个s1,是否有:(s-s1*a+s2*b) %n==0

    先看,70分代码,未进行空间优化的DP

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 using namespace std;
     5 const int MOD=1e8+7,N=1010;
     6 int f[N][100000],n,s,a,b,sum;
     7 int DP(){
     8     sum=(1+n)*n/2;
     9     for(int i=0;i<=n;i++)f[i][0]=1;
    10     for(int i=1;i<n;i++)
    11         for(int j=1;j<=sum;j++){
    12             if(i>j)f[i][j]=f[i-1][j];
    13             else f[i][j]=f[i-1][j]+f[i-1][j-i];
    14             f[i][j]%=MOD;
    15         }
    16     int ans=0;
    17     for(int s1=0;s1<=sum;s1++){
    18         int s2=sum-s1;
    19         if((s-s1*a+s2*b)%n==0)ans=(ans+f[n-1][s1])%MOD;
    20     }
    21     return ans;
    22 }
    23 int main(){
    24     cin>>n>>s>>a>>b;
    25     cout<<DP()<<endl;
    26     return 0;
    27 }

    问题就在于f数组的第二维,开不下了退而求其次只取到了1e5,实际上要到sum

    由于转移是不跨行的,我们用滚动数组的方法,就可以进行DP的空间优化了,见100分代码

    PS:对于需要检验的式子:(s-s1*a+s2*b) 是可能会爆int的,需要开ll,懒得写防爆乘了

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 using namespace std;
     5 typedef long long ll;
     6 const int MOD=1e8+7,N=600000;
     7 int f[2][N],n,s,a,b,sum;
     8 int DP(){
     9     sum=(1+n)*n/2;
    10     f[0][0]=f[1][0]=1;
    11     for(int i=1;i<n;i++){
    12         for(int j=1;j<=sum;j++)
    13             if(i>j)f[1][j]=f[0][j];
    14             else f[1][j]=(f[0][j]+f[0][j-i])%MOD;
    15         for(int j=1;j<=sum;j++)swap(f[0][j],f[1][j]);
    16     }
    17     ll ans=0;
    18     for(ll s1=0;s1<=sum;s1++){
    19         ll s2=sum-s1;
    20         if((s-s1*a+s2*b)%n==0)ans=(ans+f[0][s1])%MOD;
    21     }
    22     return ans;
    23 }
    24 int main(){
    25     cin>>n>>s>>a>>b;
    26     cout<<DP()<<endl;
    27     return 0;
    28 }
  • 相关阅读:
    dynamic和匿名对象
    生成1亿个不重复的8位随机整数
    Storage,Memcache,KVDB都是存储服务,如何区分何时用何种服务
    深入理解jQuery中$.get、$.post、$.getJSON和$.ajax的用法
    常用工具
    数字格式化,保留一位小数,无小数用0补充
    学习某些API的方法
    程序员的学习方法(程序员必看)【风中叶老师讲述】
    html的dtd声明
    数据库管理工具navicat基本使用方法——以MySql为例
  • 原文地址:https://www.cnblogs.com/JasonCow/p/12445959.html
Copyright © 2020-2023  润新知