动态规划 试题收录

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\n",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\n",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(‘\n‘);}
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;
}
时间: 2024-08-26 13:24:58

动态规划 试题收录的相关文章

.NET面试题收录

1.private.protected.public.internal修饰符的访问权限 private 私有成员,只有在类的内部可以访问 protected 保护成员,在类的内部和继承类中可以访问 public  公共成员,完全公开,没有访问限制 internal  在同一个命名空间内可以访问 2.ASP.NET页面之间传值得几种方式(Cookie .Application等) 1)QueryString QueryString是一种非常简单的传值方式,可以将传送的值暴露在浏览器地址栏,如果传递

ACM试题 - 最长公共子序列 - 动态规划方法

ACM试题题源-(最长公共子序列):http://acm.nyist.net/JudgeOnline/problem.php?pid=36 提交代码: import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner cin = new Scanner(System.in); int n = cin.nextInt(); int[] len = new int[n]; fo

小米笔试题(动态规划)

风口之下,猪都能飞.当今中国股市牛市,真可谓“错过等七年”. 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,数组中第i个元素(prices[i])代表该股票第i天的股价. 假设你一开始没有股票,但有至多两次买入1股而后卖出1股的机会,并且买入前一定要先保证手上没有股票.若两次交易机会都放弃,收益为0. 设计算法,计算你能获得的最大收益. 输入数值范围:2<=n<=100,0<=prices[i]<=100  输入例子: 3,8,5,1,7,8  

网易笔试题之合唱团---动态规划

动态规划学习 [编程题]合唱团 有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗? 输入描述: 每个输入包含 1 个测试用例.每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50).接下来的一行包含两个整数,k

说一下前天腾讯实习的笔试题--字符串回文问题(动态规划)

题目描述 最长回文子序列: 一个给定的字符串,求其最长回文子序列的长度; 一个回文子序列定义为原字符串的一个子序列去掉某些字符后生成的字符串为一个回文字符串; 例如cabbeaf:回文子序列有:c,a,aa,bb,,aba,abba,e,f,最长的就是abba,所以输出长度为4. 解题思路: 该问题为一个典型的动态规划问题,原串和反转串的最长公共子序列的长度即为该问题的解. 我实现的代码如下(我还多写了一些代码,用递归的方法来求解出了最长公共子序列的字符串): 1 #include <stdio

经典面试题楼层丢鸡蛋问题的动态规划解法与数学解法

原题: 有2个鸡蛋,从100层楼上往下扔,以此来测试鸡蛋的硬度.比如鸡蛋在第9层没有摔碎,在第10层摔碎了,那么鸡蛋不会摔碎的临界点就是9层. 问:如何用最少的尝试次数,测试出鸡蛋不会摔碎的临界点? 注意:只有两个鸡蛋.第一个鸡蛋碎了,第二个鸡蛋只能挨个楼层测试了. 动态规划解法: //height为楼层数 const int maxHeight = 100; int dp[maxHeight + 5] = { 0 }; for (int height = 1; height <= maxHei

算法初级面试题08——递归和动态规划的精髓、阶乘、汉诺塔、子序列和全排列、母牛问题、逆序栈、最小的路径和、数组累加成指定整数、背包问题

第八课主要介绍递归和动态规划 介绍递归和动态规划 暴力递归: 1,把问题转化为规模缩小了的同类问题的子问题 2,有明确的不需要继续进行递归的条件(base case) 3,有当得到了子问题的结果之后的决策过程 4,不记录每一个子问题的解 动态规划 1,从暴力递归中来 2,将每一个子问题的解记录下来,避免重复计算 3,把暴力递归的过程,抽象成了状态表达 4,并且存在化简状态表达,使其更加简洁的可能 图灵引入的是:我不知道怎么算,但是我知道怎么试.知道怎么暴力破解出来. 要学会,练习懂得怎么尝试.

动态规划:面试题42. 连续子数组的最大和

面试题42. 连续子数组的最大和 题目要求: 解题思路: 1. 定义子问题: dp[i] 为下标以 num[i] 结尾的数组字段 元素最大最短和,i表示子段到当前i位置 i: 2. 寻找关系式: 只有一个元素:dp[0] = num[0]; 两个元素:dp[i] 为num[0], num[1], num[0]+num[1]; 三个元素时:考虑前三个元素,如何求其最?大?子段和?还是分为两种情况讨论,第三个元素在最后的字串串内吗? 若第三个元素也包含在最后的字串串内,则dp[2] = max(dp

Linux运维常见面试题之精华收录

1.什么是运维?什么是游戏运维? 1)运维是指大型组织已经建立好的网络软硬件的维护,就是要保证业务的上线与运作的正常,在他运转的过程中,对他进行维护,他集合了网络.系统.数据库.开发.安全.监控于一身的技术运维又包括很多种,有DBA运维.网站运维.虚拟化运维.监控运维.游戏运维等等 2)游戏运维又有分工,分为开发运维.应用运维(业务运维)和系统运维开发运维:是给应用运维开发运维工具和运维平台的应用运维:是给业务上线.维护和做故障排除的,用开发运维开发出来的工具给业务上线.维护.做故障排查系统运维