ICPC2018 Nakhon Pathom(泰国佛统区域赛)- Evolution Game(进化游戏)(状态转移方程)

探讨在一个拥有魔法野兽的奇幻世界中,野兽如何通过改变形态变得更强大,以及它们最多能进化多少次。此问题转化为一个复杂的算法问题,涉及到状态转移的概念,通过排序和动态规划解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

In the fantasy world of ICPC there are magical beasts. As they grow, these beasts can change form, and every time they do they become more powerful. A beast cannot change form completely arbitrarily though. In each form a beast has n eyes and k horns, and these affect the changes it can make.  

在奇妙的ICPC世界里有很多神奇的野兽。当他们生长时,这些野兽可以转换形态(口 袋 妖 怪),以及每次他们进化的时候他们都会变得更强,但一个野兽不能彻底随意地改变形态,在每种形态下一个野兽有n只眼和k个角,这也会影响它的进化路径。
 
A beast can only change to a form with more horns than it currently has. 

一个接受只能进化成角多(严格大于)的形态
A beast can only change to a form that has a difference of at most w eyes. So, if the beast currently has n eyes it can change to a form with eyes in range [n - w, n + w]. 
 一只野兽进化的形态必须与前驱形态相差w个眼之内,这也就是说,如果这个野兽现在有n只眼,它可以进化为一种有 [n - w, n + w]个眼的形态。
A beast has one form for every number of eyes between 1 and N, and these forms will also have an associated number of horns. A beast can be born in any form. The question is, how powerful can one of these beasts become? In other words, how many times can a beast change form before it runs out of possibilities? 

一个野兽在眼数1-N都有一种形态,以及这些形态也有一个与之相关的角数。一个野兽的初始形态不定。问题是,这些野兽里最强的那个会变成什么样?换句话说,这些野兽最多可以进化多少次,在他们耗尽可能性之前的话?

输入

The first line contains two integers, N and w, that indicate, respectively, the maximum eye number, and the maximum eye difference allowed in a change (1 ≤ N ≤ 5000; 0 ≤ w ≤ N).  

第一行包含两个整数,n和w,这分别代表最大眼数和允许的最大眼数的变更范围。
The next line contains N integers which represent the number of horns in each form. I.e. the ith number, h(i), is the number of horns the form with i eyes has (1 ≤ h(i) ≤ 1 000 000). 

接下来的N个整数代表每个形态下的角数,换言之,第i个数,h(i)是一种形态,有i个眼和h(i)个角。

输出

For each test case, display one line containing the maximum possible number of changes. 

对于每组样例,输出最大可能进化数。

输入

5 5
5 3 2 1 4

输出

4

hint

Start with 1 horn and 4 eyes, and it can change 4 times: (1 horn 4 eyes) -> (2 horns 3 eyes) -> (3 horns 2 eyes) -> (4 horns 5 eyes) -> (5 horns 1 eye). 

  干不干的掉这个题就要看对“状态转移”这个概念理解深不深刻了。状态转移说白了就是一种状态变到另一种状态,但是由于状态间的关系可能很复杂,所以一般的for循环暴力可能无法遍及所有可能性。这里我们就以各种形态为一种状态来研究到达这个状态的途径有多少种。

   首先由题意知:进化肯定是从少角到多角,但是初始形态不明,这也就与不定点求最长上升子序列类似(这里用不到它的操作方法),所以我们以各点为一种状态,并将“状态”实时更新为访问这个状态时的两个值(原值与试图更新的值)的最大值。而这个最大值可以以别的形态为起点的时候继续扩展,从而得到最终的最大值。

所以基本思路如下:

  1. 对整组数据以角的数量从小到大排序。
  2. 从最小角开始,以当前角数为起点向后遍历,遍历时进行判断,并用一个数组储存当前状态(dp数组),并把已经当过起点的状态标记,使得在接下来的循环中不会再访问他。
  3. 寻找下一个起点,每一个点都必须当做起点一次。

代码如下:

#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include <queue>
#include <algorithm>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf("%lld",&a)
#define din(a) scanf("%d",&a)
#define printlnlld(a) printf("%lld\n",a)
#define printlnd(a) printf("%d\n",a)
#define printlld(a) printf("%lld",a)
#define printd(a) printf("%d",a)
#define reset(a,b) memset(a,b,sizeof(a))
const int INF=0x3f3f3f3f;
using namespace std;
const double PI=acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod=1000000007;
///Schlacht von Stalingrad
/**Although there will be many obstructs ahead,
the desire for victory still fills you with determination..**/
ll dp[7000];
bool vis[7000];
struct form
{
    ll horn,eye;
}forms[5009];
bool cmp(form a,form b)
{
    return a.horn<b.horn;
}
int DETERMINATION()
{
    ll n,w;
    cin>>n>>w;
    for(int i=1; i<=n; i++)
    {
        cin>>forms[i].horn;
        forms[i].eye=i;
    }
    ll ans=-1;
    ll tmp=n,current=1;
    sort(forms+1,forms+1+n,cmp);//按角排序
    while(tmp--)//保证每个点都可以当做起点
    {
        for(int i=1; i<=n; i++)
        {
            if(forms[current].horn<forms[i].horn&&!vis[forms[current].eye])//判断条件
                if(abs(forms[current].eye-forms[i].eye)<=w)
                {
                    dp[forms[i].eye]=max(dp[forms[i].eye],dp[forms[current].eye]+1);
                 //核心:状态转移方程——由current状态延伸出的各种结果
                }
        }
        vis[forms[current].eye]=1;//标记
        current++;//由于早已有序,所以直接把指针后移即可(由小向大)
    }
    for(int i=1;i<=n;i++)
        ans=max(ans,dp[forms[i].eye]);
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值