zoukankan      html  css  js  c++  java
  • 动态规划 试题收录

    DP稀烂也不是一天两天了

    我觉得我很有必要把做(chao)过的DP记录下来啊... ...DP这种精细的东西真是太玄妙了。

    慢慢来吧。只有思维足够强大,才足以见题拆题。

    编辑中... ...

    树形DP:

    1.机器人采集金属

    分析:设 f[i][j] 为:遍历完j的子树,且剩下i个回到j的最小代价。特殊的,f[0][i]表示用一个机器人走完所有节点再回来的代价,原因是每个点都必须且只能转移一种对答案贡献的状态。

    那么状态转移方程就要分两类讨论。

    初始化:f[i][x]=sigma(f[0][son_i]);

    维护:f[i][k]=min(f[i][k],f[i-j][son_i]+f[j][son_i]+j*Edge_val;

    想想真的很妙啊。

    #include    <iostream>
    #include    <cstdio>
    #include    <cstdlib>
    #include    <algorithm>
    #include    <vector>
    #include    <cstring>
    #include    <queue>
    #define LL long long int
    #define ls (x << 1)
    #define rs (x << 1 | 1)
    using namespace std;
    const int N = 100010;
    struct Node{int to;LL val;int next;}E[N];
    int n,S,K,tot,head[N];LL f[21][N];
    int gi()
    {
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    LL gL()
    {
      LL x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    inline void link(int u,int v,LL w)
    {
      E[++tot]=(Node){v,w,head[u]};
      head[u]=tot;
    }
    inline void dfs(int x,int fa)
    {
      for(int e=head[x];e;e=E[e].next)
        {
          int now=E[e].to;
          if(now==fa)continue;
          dfs(now,x);
          for(int k=K;k>=0;--k)
    	{
    	  f[k][x]+=f[0][now]+2*E[e].val;
    	  for(int i=1;i<=k;++i)
    	    f[k][x]=min(f[k][x],f[k-i][x]+f[i][now]+i*E[e].val);
    	}
        }
    }
    int main()
    {
      //freopen("input.txt","r",stdin);
      //freopen("output.txt","w",stdout);
      n=gi();S=gi();K=gi();
      for(int i=1;i<n;++i)
        {
          int u=gi(),v=gi();LL w=gL();
          link(u,v,w);link(v,u,w);
        }
      dfs(S,S);printf("%lld
    ",f[K][S]);
      
      /*fclose(stdin);
        fclose(stdout);*/
      return 0;
    }
    

    背包问题

    1.多重背包计数

    考场上只打了一个01背包的暴力,但是明显没什么卵用。

    然后好像RG说是FFT?弱的抠脚... ...

    不过Nick讲了一种十分高明的做法:分块。

    考场上我在想能不能直接把N/2的枝减掉,Nick说我可以大胆剪刀根号级。

    对于根号之前的就直接暴力肛。这样前半截的复杂度在数据不超过2000下没有压力(实在是不会分析了)。

    对于根号后的,记录g[i][j]表示使用i个,体积和为j的方案数。然后显然i顶多到根号n。

    转移方程也是十分巧妙,给我一种点科技树的感觉。

    1.加入一个体积为根号的物品;

    2.背包内每个东西的值都变成其+1;

    是不是巧妙无比?我是被吓到了/*哦吼*/。对了记得g[1][0](G10);

    统计答案的时候,用乘法原理+加法原理,前半部分和后半部分搞一下。

    #include    <iostream>
    #include    <cstdio>
    #include    <cstdlib>
    #include    <algorithm>
    #include    <vector>
    #include    <cstring>
    #include    <queue>
    #include    <cmath>
    #define LL long long int
    #define ls (x << 1)
    #define rs (x << 1 | 1)
    using namespace std;
    const int N = 100010;
    const int Mod = 23333333;
    LL f[5][N],g[320][N],n,lim,sum[N],now;
    int gi()
    {
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    void pui(int x)
    {
      if(x<10)putchar(x+'0');
      else pui(x/10),putchar(x%10+'0');
    }
    LL gL()
    {
      LL x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    inline void work1()
    {
      for(int i=1;i<=lim;++i)
        {
          now^=1;memset(sum,0,sizeof(sum));
          for(int j=0;j<=n;++j)
    	{
    	  f[now][j]=(sum[j%i]+f[now^1][j])%Mod;
    	  if(j<i*i)sum[j%i]=(sum[j%i]+f[now^1][j])%Mod;
    	  else sum[j%i]=((sum[j%i]-f[now^1][j-i*i]+f[now^1][j])%Mod+Mod)%Mod;
    	}
        }
    }
    inline void work2()
    {
      for(int i=0;i<=lim;++i)
        for(int j=0;j<=n;++j)
          {
    	if(i&&i+j<=n)g[i][i+j]=(g[i][i+j]+g[i][j])%Mod;
    	if(j+lim+1<=n)g[i+1][j+lim+1]=(g[i+1][j+lim+1]+g[i][j])%Mod;
          }
      ++g[1][0];
    }
    inline void calcans()
    {
      LL Ans=0;
      for(int i=0;i<=n;++i)
        for(int j=1;j<=lim;++j)
          Ans=(Ans+((LL)f[now][i]*(LL)g[j][n-i])%Mod)%Mod;
      printf("%lld
    ",Ans);
    }
    int main()
    {
      n=gi();lim=sqrt(n);f[0][0]=g[0][0]=1;
      work1();work2();calcans();return 0;
    }
    

    数学等类

    1.机器人m号

    这题的正解有两种,DP和递推(其实也是一个DP)。关于第二种,我发现它的状态设置的十分巧妙,对欧拉函数的积性运用到了很高的境界。

    容易发现独立数就是欧拉函数。所以答案就是要求一个数的所有因子:

    1.由奇数个不同的奇质因子组成的因子的欧拉函数的和。

    2.由偶数个不同的奇质因子组成的因子的欧拉函数的和。

    3.其他所有因子的欧拉函数的和。

    然后由欧拉函数的性质我们发现第3个不用求,重点在前两个。

    用莫比乌斯函数推是没用的,因为没有2。可以考虑DP;

    朴素的DP就是f[i][j]表示推到第i个质数,由j个不同奇质数组成的数的欧拉函数和,然后答案就是两个累加。这也是很巧妙的利用了积性。

    第二种就更加简单粗暴,但这正是世界的美丽。设Ans1和Ans2分别就是f对应的奇偶状态的和。一路读入一路递推就可以了。递推式也简介务必让人shiniao未及,吓得我一抖一抖的。

    #include    <iostream>
    #include    <cstdio>
    #include    <cstdlib>
    #include    <algorithm>
    #include    <vector>
    #include    <cstring>
    #include    <queue>
    #define LL long long int
    #define ls (x << 1)
    #define rs (x << 1 | 1)
    using namespace std;
    const LL Mod = 10000;
    LL F[1010][1010],Ans1,Ans2,m,k;
    int gi()
    {
      int x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    void pL(LL x)
    {
      if(x<0)putchar('-'),pL(-x);
      if(x<10)putchar(x+'0');
      else pL(x/10),putchar(x%10+'0');
    }
    void pc(){putchar('
    ');}
    LL gL()
    {
      LL x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    LL Qpow(LL d,LL z)
    {
      LL ans=1;
      for(;z;z>>=1,d=d*d%Mod)if(z&1)ans=ans*d%Mod;
      return ans;
    }
    int main()
    {
      k=gL();m=1;
      for(LL i=1;i<=k;++i)
        {
          LL p=gL(),e=gL();
          m=m*Qpow(p,e)%Mod;
          if(p==2)continue;
          LL ans1=(Ans1+(Ans2+1)*(p-1))%Mod;
          LL ans2=(Ans2+Ans1*(p-1))%Mod;
          Ans1=ans1;Ans2=ans2;
        }
      pL(Ans2);pc();pL(Ans1);pc();pL(((m-Ans1-Ans2-1)%Mod+Mod)%Mod);
      return 0;
    }
    
  • 相关阅读:
    Oracle 11g db_ultra_safe参数
    How To Configure NTP On Windows 2008 R2 (zt)
    Brocade光纤交换机密码重置 (ZT)
    perl如何访问Oracle (ZT)
    Nagios check_nrpe : Socket timeout after 10 seconds
    oracle10g单机使用ASM存储数据
    Xmanager无法连接Solaris10 (ZT)
    Solaris10配置iscsi initiator
    oracle 11g dataguard 创建过程
    Nagios check_procs pst3 报错
  • 原文地址:https://www.cnblogs.com/fenghaoran/p/6664455.html
Copyright © 2011-2022 走看看