zoukankan      html  css  js  c++  java
  • USACO动态规划二测总结

    前言+总结

    这次七点半开始,两个半小时四道题,最终156.xxx哭唧唧。被硕神虐到爆。scy说有一道AC自动机+dp,好了蒟蒻还没搞自动姬呢!翻了下题目,嗯第四题,看了几眼不怎么看懂又不会自动姬就先直接判死刑。

    先打的第一题,画了一下发现是看斜率的,样例解释坑死。打了个O(n^2)的dp,看了范围手动测了几组数据目测能过,下一题!啊第二题应该是个三维dp,我写了下状态,感觉状态转移有点虚(莫名慌)。于是去打了暴力(贪心那种)发现样例调都不对,真的一直调调到八点半快九点了!(没有发现样例就在卡贪心= =)然后先跳过打第三题,最后只想到了乱搞搞到O(n^2),明显超时的算法,但是目前来看无论能不能A先骗分吧。滚回去调第二题暴力,发现了贪心bug,改了一下过样例后就去虚一下三维dp,样例很快过了,手动和暴力对拍了几下。时间也就剩几分钟了。就这样吧。

    最后,发现,第一次存斜率的初始化!!清成0了可能是负数的啊QWQ 第二题for循环打反了反了!我不会说一开始打对了,打着打着方程觉得应该反过来还觉得幸好自己发现了有点机智的(= =简直mdzz啊) 第三题n方算法有50分也算意料之中,第一二题跪到只有一半分orzorzorz(可能应该说居然这样还有一半分)

    感觉总结没什么好说总结嘛,多吃核桃弥补脑子残疾,把还没搞的算法学完。细节要多考虑!

    题意+题解

    第一题bzoj 1721[Usaco2006 Mar]Ski Lift 缆车支柱


    解释那里的 因为9海拔较高 有误啊!应该是因为较低吧。

    这个我的算法跟别人的有点不一样,O(nm)≈O(n^2)吧也。

    设sp[j]表示j后面的点到j的斜率的最大值,随着dp不断更新,并不是预处理。

    f[i]表示在i点建站,且搞定之前所要建的个数。

    明显方程就是f[i]=min(f[i],f[j]+1); 

    j扫i的前m个,判断i到j的斜率是否大于i前面的点到j的最大斜率,这个时候就用到了sp[j],随便更新sp[j]。

    附代码

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    #define maxn 5100
    
    LL mymin(LL x,LL y){return (x<y)?x:y;}
    LL f[maxn],h[maxn];double sp[maxn];
    double slop(int j1,int j2)
    {
    	return 1.0*(h[j2]-h[j1])/(j2-j1);
    }
    int main()
    {
    	//freopen("skilift.in","r",stdin);
    	//freopen("skilift.out","w",stdout);
    	int n,m,i,j;
    	scanf("%d%d",&n,&m);
    	for (i=1;i<=n;i++)
    	{
    		scanf("%I64d",&h[i]);
    		if (i!=1) sp[i-1]=slop(i-1,i);
    	}
    	memset(f,63,sizeof(f));
    	f[1]=1;
    	for (i=2;i<=n;i++)
    	{
    		for (j=1;j<=m;j++)
    		 if (i>j)
    		 {
    		 	double ls=slop(i-j,i);
    		 	if (ls>=sp[i-j]) 
    			{
    				f[i]=mymin(f[i],f[i-j]+1);
    				sp[i-j]=ls;
    			}
    		 }else break;
    		f[i]=mymin(f[i],f[i-1]+1);
    	}printf("%I64d
    ",f[n]);
    	return 0;
    }
    

    =========================================

    第二题poj 1946 Cow Cycling


    三维dp,真的我觉得我的代码和做法比cgh的好多了!233

    设f[i][j][k]表示用到第i只牛来当队首,j为队首剩下的体力,k为已经绕了多少圈。

    枚举速度,方程就很容易写出来了。

    然后要记得把换个队首的传下去。

    代码里被屏蔽的那部分就是一开始打的暴力orz,能过一半点!

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    int n,m,s,ans;
    int f[30][110][110];
    int mymin(int x,int y){return (x<y)?x:y;}
    /*void baoli(int x,int ds,int qs,int t)
    {
    	if (qs>=s) {ans=mymin(ans,t);return;}
    	if (x==0) return;
    	int orz=sqrt(ds);
    	if ((s-qs)*(s-qs)<=ds) {ans=mymin(ans,t+1);return;}
    	for (int i=orz;i>=1;i--)
    	 baoli(x,ds-i*i,qs+i,t+1);
    	baoli(x-1,m-qs,qs,t);
    }*/
    int main()
    {
    	//freopen("cycling.in","r",stdin);
    	//freopen("cycling.out","w",stdout);
    	int i,j,k,ii;
    	scanf("%d%d%d",&n,&m,&s);
    	//ans=s;baoli(n,m,0,0);
    	memset(f,63,sizeof(f));
    	f[1][m][0]=0;ans=s;
    	for (i=1;i<=n;i++)//枚举队首用到了第几只牛
    	  for (j=m;j>=0;j--)//队首体力剩多少
    	  { 
    		for (ii=0;ii<=s;ii++)//已经绕了第几圈
    	        {
    		   for (k=1;k*k<=j;k++)//枚举下一分钟的速度
    	             f[i][j-k*k][ii+k]=mymin(f[i][j-k*k][ii+k],f[i][j][ii]+1);
    		   f[i+1][m-ii][ii]=mymin(f[i+1][m-ii][ii],f[i][j][ii]);
    		}ans=mymin(ans,f[i][j][s]);
    	  }
    	printf("%d
    ",ans);
    	return 0;
    }
    
    ==========================================

    第三题bzoj1587[Usaco2009 Mar]Cleaning Up 打扫卫生


    这道题,可以想到分n个最多花的时间就是n嘛~如果超过的话我不如一个一个来打扫呢对吧。(这个我想到了!但是后面的就不行了去问了奥爷爷和男神还是不懂啊还说不是zz!qwq)所以分n个的话这其中的颜色种类个数不能超过根号n个。

    先预处理与此同色的上一个位置和后一个位置。

    设pos[],pos[]记录的是扫的这段中某种颜色第一次出现的位置。num[i]为pos[i]~目前扫到的位置间不同颜色种类的个数。诶诶诶好难表达啊语文不好啊><><><具体看代码意会orz

    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define maxn 40100
    
    int w[maxn],a[maxn],f[maxn],nt[maxn];
    int pos[maxn],num[maxn],pre[maxn];
    int mymin(int x,int y){return (x<y)?x:y;}
    int main()
    {
    	//freopen("cleanup.in","r",stdin);
    	//freopen("cleanup.out","w",stdout);
    	int n,m,i,j,K;
    	scanf("%d%d",&n,&m);
    	memset(f,63,sizeof(f));
    	memset(nt,63,sizeof(nt));
    	memset(w,-1,sizeof(w));
    	for (i=1;i<=n;i++)
    	{
    		scanf("%d",&a[i]);
    		nt[w[a[i]]]=i;
    		pre[i]=w[a[i]];w[a[i]]=i;
    	}f[1]=1;K=floor(sqrt(n));
    	for (i=1;i<=K;i++) pos[i]=1,num[i]=1;
    	for (i=2;i<=n;i++)
    	{
    		for (j=1;j<=K;j++)//枚举前面的颜色种数,不能超过K=根号n
    		{
    			if (pre[i]<pos[j])//看看在i位置的这种颜色的上一个位置在不在区间内
    			{
    				num[j]++;//如果不在就说明这个区间内的颜色种类+1
    				if (num[j]>j) //超出限制的话就要删掉最前面的一种颜色
    				{
    					while (nt[pos[j]]<=i) pos[j]++;
    					pos[j]++;num[j]--;
    				}
    			}f[i]=mymin(f[i],f[pos[j]-1]+num[j]*num[j]);
    		}
    	}printf("%d
    ",f[n]);
    	return 0;
    }
    

    诶这个本来是昨晚打的,为了国庆!今天发!随便祝祖国生快!~(≧▽≦)/~啦啦啦~

  • 相关阅读:
    中型PLC运控快速入门系列教程------第3节 编程语法样例讲解
    中型PLC运控快速入门系列教程------第2节 常用数据类型及变量介绍
    中型PLC运控快速入门系列教程------第1节 学习指南资料介绍
    Inoproshop入门系列教程-----第11节 中型PLC常用快捷方式介绍
    Inoproshop入门系列教程-----第10节 程序安全加密和解锁
    Inoproshop入门系列教程-----第9节 变量关联IO和掉电保持
    Inoproshop入门系列教程-----第8节 中型PLC固件升级方式
    Inoproshop入门系列教程-----第7节 库文件的安装及设备文件的导入
    Inoproshop入门系列教程-----第6节 通信等组态配置介绍
    Inoproshop入门系列教程-----第5节 流水灯样例快速编程上手
  • 原文地址:https://www.cnblogs.com/Euryale-Rose/p/6527858.html
Copyright © 2011-2022 走看看