noip难度的dp题(怎么全是usaco的?)

概述:

这次我特别的稳~~
1,2,4三道没有思维难度的水题都拿到了满分;
再骗个20,就拿到了这次的第二名~


顺序

  • 1.接苹果
  • 2.奶牛飞盘队
  • 3.股票市场
  • 4.248
  • 5.262144

1.接苹果

【问题描述】

奶牛喜欢吃苹果。约翰有两棵苹果树,有 N 只苹果会从树上陆续落下。如果掉苹果的时候,贝西在那棵树下,她就能接住苹果。贝西一开始在第一棵树下。在苹果掉落之前,她有足够的时间来回走动,但她很懒,最多只愿意移动 K 次。请计算一下她最多可以接住几只苹果。

【输入】

• 第一行:两个整数 N 和 K,1 ≤ N ≤ 1000; 1 ≤ K ≤ 30
• 第 i + 1 行有一个整数 Ti,表示第 i 只苹果从哪棵树上掉落,1 表示从第一棵树,2 表示从第二棵树

【输出】

单个整数:表示能接住的最大苹果数量

【输入输出样例1】
bcatch. in

7 2
2
1
1
2
2
1
1

bcatch. out

6

线性暴力dp

#include 
using namespace std ;
const int N=1e3+5;
int a[N],f[N][35][3];
int n,m,k,ans=0,i,j;
int main()
{
//	freopen("bcatch.in","r",stdin);
//	freopen("bcatch.out","w",stdout);
	
	
	for(scanf("%d%d",&n,&k),i=0;++i<=n;)scanf("%d",&a[i]);
	if(a[1]==1)f[1][0][1]=1,f[1][1][1]=1,f[1][0][2]=0;
	if(a[1]==2)f[1][0][2]=1,f[1][1][2]=1,f[1][0][1]=0;
	
	for(i=0;++i<=n;)
	{
	  for(j=-1;++j<=k;)
	  {
		if(a[i]==1)
		{
		  f[i][j][2]=max(f[i-1][j][2],f[i][j][2]);
		  f[i][j][1]=max(f[i-1][j][1]+1,f[i][j][1]);
		  if(j!=k)f[i][j][1]=max(f[i][j][1],f[i-1][j+1][2]+1);
		}
		else 
		{
		  f[i][j][1]=max(f[i-1][j][1],f[i][j][1]);
		  f[i][j][2]=max(f[i-1][j][2]+1,f[i][j][2]);
		  if(j!=k)f[i][j][2]=max(f[i][j][2],f[i-1][j+1][1]+1);
		}
	  }
	}
	
	for(i=-1;++i<=k;)ans=max(ans,max(f[n][i][1],f[n][i][2]));
	
	printf("%d",ans);
	return 0;
}



2.奶牛飞盘队

【问题描述】

农夫顿因开始玩飞盘之后,约翰也打算让奶牛们享受飞盘的乐趣.他要组建一只奶牛飞盘队.
他的N(1≤N≤2000)只奶牛,每只部有一个飞盘水准指数Ri(1≤Ri≤100000).约翰要选出1只或多于1只奶牛来参加他的飞盘队.
约翰比较迷信,他的幸运数字是F,所以他要求队伍的总能力必须是F的倍数。请帮他算一下,符合这个要求的队伍组合有多少?由于这个数字很大,只要输出答案除以10^8 的余数就可以了。

【输入】

第一行:两个用空格分开的整数:N和F,1 ≤ N ≤ 2000,1 ≤ F ≤ 1000
第二行到N + 1行:第i + 1行有一个整数R i ,表示第i头奶牛的能力,1 ≤ R i ≤ 10^5

【输出】

10*10

【输入输出样例1】
fristeam. in

4 5
1
2
8
2

fristeam. out

3

全盘第二水的题,必须过,注意简单的不正宗状压一下

#include
using namespace std;
const int N=2e3+5;
const int MOD=1e8;
int n,m,i,j,k,len,ans,sum=0;
int a[N],f[N][N];
bool bo[N];
int main()
{
//	freopen("fristeam.in","r",stdin);
//	freopen("fristeam.out","w",stdout); 
	
    for(scanf("%d%d",&n,&m),i=0;++i<=n;)
    {
        
        for(scanf("%d",&k),f[i][k%m]=1,j=-1;++j<m;)
        {
            f[i][j]=(f[i][j]+f[i-1][j])%MOD;
            f[i][(j+k)%m]=(f[i][(j+k)%m]+f[i-1][j])%MOD;
        }
    }
    printf("%d",f[n][0]);
	
	return 0;
}

3.股票市场

noip难度的dp题(怎么全是usaco的?)_第1张图片noip难度的dp题(怎么全是usaco的?)_第2张图片

【输入输出样例1】
stock. in

2 3 10
10 15 15
13 11 20

stock.out

24
思维方面很难,但看透了,不过就是个背包

#include
using namespace std;
const int N=2e6+5;
int f[N],a[102][102];
int n,m,k,i,j,s,d;
int main()
{
//	freopen("stock.in","r",stdin);
//	freopen("stock.out","w",stdout); 
    
    
    for(scanf("%d%d%d",&n,&d,&m),i=0;++i<=n;)
      for(j=0;++j<=d;)
        scanf("%d",&a[j][i]);
        
    for(k=0;++k<d;)
    {
    	for(memset(f,0,sizeof(f)),i=0;++i<=n;)
    	  for(j=a[k][i]-1;++j<=m;)
    	    f[j]=max(f[j],f[j-a[k][i]]+a[k+1][i]-a[k][i]);
    	m+=f[m];
	}
    printf("%d",m);
    
	return 0;
}

4.248

【问题描述】

给定一个1*N(2<=N<=248) 的地图,在里面玩2048,每次可以合并相邻两个(数值范围1-40),问最大能合出多少。注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3。

【输入】

第一行,一个整数N
接下来N行,每行一个整数,表示第i个数字

【输出】

所求的答案

【输入输出样例1】
248. in

4
1
1
1
2

248. out

3
应该是最基础的了吧,跟石子合并一样难的区间dp

#include 
using namespace std;
const int N=248+5;
int n,m,i,j,k,l,ans;
int f[N][N];
int main()
{
	freopen("248.in","r",stdin);
	freopen("248.out","w",stdout); 
	for(scanf("%d",&n),i=0;++i<=n;)scanf("%d",&f[i][i]);

    for(i=0;++i<n;)
    {
    	for(j=0;++j<=n;)
    	{
    		l=j+i;
			if(l>n)break;
    		for(k=j-1;++k<l;)
			{
			   if(!(f[j][k]^f[k+1][l]))
			   {
			      f[j][l]=max(f[j][l],f[j][k]+1);
			      ans=max(ans,f[j][l]);
			   } 	
			} 
		}
	}
	printf("%d",ans);
	
	return 0;
}

5.262144

【问题描述】

noip难度的dp题(怎么全是usaco的?)_第3张图片

【输入】

第一行,一个整数N
接下来N行,每行一个整数,表示第i个数字

【输出】

所求的答案

【输入输出样例1】
262144. in

4
1
1
1
2

262144. out

3
这道题跟上一题,题意一样,但数据打了不少?怎么dp》》》
这个东西考试时候没有做出来,但没有想到竟然会短
嗯,仅仅是短:
https://www.cnblogs.com/Achensy/p/10804621.html
分享一位比较厉害的人写的题解


谢谢~~

没有颜色才是纯

你可能感兴趣的:(测试,程序,dp)