计蒜客暑假集训第一阶段第五场 f题

Emma just discovered a new card game called Gwint: A wizard’s game. There are two types of cards: monster cards and spell cards. Monster cards are used to score points, while spell cards typically interact with the monsters in some way.

On each monster card there is an integer value, the power of the monster. Monsters can fight each other, and during these fights the power acts as both the strength and the health of the monster. The monsters take turns hitting each other until one of them dies. Whenever a monster AA hits a monster BB, this causes BB to lose an amount of power equal to the power of AA. Conversely, if BB hits AA, AA loses power equal to the power of BB (see the example below). This continues until one of the two monsters has a power of zero or less, at which point this monster is considered dead. 
这里写图片描述
One of Emma’s most beloved cards in the game is a spell called Fight! which states:

Pick two monsters. They fight each other to the death. If the surviving monster has a power of exactly 11 left, return this card to your hand.

Of course, Emma would like to play as efficiently as possible by picking two monsters such that Fight! is returned to her hand. However, there are often a lot of monsters on the board, which makes it very time consuming to figure out whether this can be done or not. Can you help her find two monsters she can pick so that she gets the card back?

Input Format 
The input consists of:one line with an integer nn (2 \le n \le 10^5)(2≤n≤10 5), the number of monsters;one line with nn integers m_1, \cdots, m_nm 1 ,⋯,m n(1 \le m_i \le 10^6)(1≤m i ≤10 6 ), giving the power of each monster.

Output Format 
If there is no pair of monsters that Emma can pick, output impossible. Otherwise, output two distinct integers ii, jj (1 \le i, j \le n)(1≤i,j≤n), where ii is the index of the monster that starts the fight and jj is the index of the other monster. If multiple solutions exist, print the minimum pair(i,j)(i,j).

样例输入1 

1 12 67 8 
样例输出1 
impossible 
样例输入2 

1 1 12 67 8 
样例输出2 
2 1 
样例输入3 

1 5 6 7 90 8 
样例输出3 
2 6

题意:

输入n表示n个怪物,在输入n个值表示怪物的生命值和其攻击力,接下来是重点:由小的怪物攻击大的怪物,大怪物hp和attact都变为两者之差,接着原先大的怪物(注意哟原先大怪物的值变了也)攻击原先小的怪物,好像有点啰嗦耶,如此往复,看上图你就明白了,如果存在两个怪物进行如上操作后,有一个变为1,一个小于等于0,则输出这两个的编号,如果有多个输出最小的。

思路:

AC思路:

我们从后往前推;

我们可以看到,如果要满足最后的条件,那么两个数必须是连续的斐波那契数,那么问题就变成了判断给定的一串数字中是否有两个连续的斐波那契数,如果有,输出他们的下表索引,如果没有,输出impossible。

自己想的思路:

看到这个题,我第一时间想的就是模拟,遍历所有的情况,然后模拟他说的过程,如果满足条件,就输出。但是交上后,超时,然后我开始优化,通过观察发现,如果两个数,前面的数大于后面的数,那么肯定不满足条件,砍掉,然后发现,如果每次攻击完后,被攻击的怪兽的攻击力如果还大于攻击的怪兽的体力,那么肯定也不满足,砍掉,交上后,还是超时,郁闷了。比赛结束后,通过看题解和别人写的博客,最终成功解决这个题目。

代码:

AC代码:

#include<bits/stdc++.h>
#define MAXN 1000010
using namespace std;
int n;
int k;//斐波那契数的个数
int c=0;
int f[40];//求斐波那契数列的数组
int t1;
int pai[MAXN];//pai[i]代表值为i的元素第一次输入时的序号
int com[MAXN];//com[i]代表值为i的元素一共出现了几次
int main()
{
    f[0]=1;
    f[1]=1;
    for(int i=2;;i++)//求斐波那契数列
    {
        f[i]=f[i-2]+f[i-1];
        if(f[i]>=1e6)//所求的斐波那契数如果大于1e6,就不用求了
        {
            k=i+1;//记录所求的斐波那契数的个数
            break ;
        }
    }
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>t1;
        if(pai[t1]==0)//如果这个条件满足,说明前面还没有输入t1这个值,如果这个条件不满足,我们也不会更新pai[t1]了,因为如果不满足,说明前面已经有t1输入了,我们pai[t1]记录的是第一次输入t1时的序号,所以不会更新pai[t1]了
            pai[t1]=i;
        else
        {
            if(t1==1&&pai[0]==0)//对于斐波那契数列,有一个特殊情况,那就是刚开始的两个1,对于这种特殊情况,我们必须特殊处理,如果这个条件满足,说明前面已经输入一个1了,现在又输入一个1,我们存在pai[0]位置(这里的pai[0]代表的是第二个1)
                pai[0]=i;
        }
        com[t1]++;//累加次数
    }
    if(com[1]>=2)//这个if语句是判断斐波那契数列的特殊情况的  刚开始的两个1
    {
        cout<<pai[1]<<" "<<pai[0];//输出下标的索引
        c=1;
    }
    else//接下来就是一般的情况,我们这里遍历所有求出的斐波那契数列,因为只有30几个,时间复杂度不会太高
    {
        for(int j=2;j<=k;j++)
        {
            if(com[f[j]]>=1&&com[f[j-1]]>=1)//这个条件如果满足,说明所给的数列中有两个连续的斐波那契数,这里就像是一个递推,查看j位置和j-1位置的斐波那契数
            {
                c=1;
                cout<<pai[f[j-1]]<<" "<<pai[f[j]];//由于题目规定的是如果有多组结果,输出两个斐波那契数和最小的下标的索引,而且先输出的两个斐波那契数中小的那个的下标的索引,然后输出大的那个斐波那契数的下标索引
                break ;
            }
        }
    }
    if(!c)
        cout<<"impossible";
}

超时代码:

#include<bits/stdc++.h>
#define MAXN 200010
using namespace std;
int n;
int tz=0;
int c,v;
int sum=MAXN;
int root[MAXN];
void dou(int z,int k)
{
    int z1=root[z];
    int k1=root[k];
    int t=0;
    while (z1>0&&k1>0)
    {
        if(z1==1&&k1==1)
        {
            tz++;
            if(sum>z+k)
            {
                c=z;
                v=k;
            }
        }
        if(t==0)
        {
            k1-=z1;
            if(2*k1<z1)
                return ;
            t=1;
        }
        else
        {
            z1-=k1;
            if(2*z1<k1)
                return ;
            t=0;
        }
    }
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>root[i];
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(i==j||(2*root[i])<=root[j]||root[i]>root[j])
                continue ;
            dou(i,j);
        }
    }
    if(tz==0)
        cout<<"impossible";
    else
        cout<<c<<" "<<v;
}

猜你喜欢

转载自blog.csdn.net/qq_40938077/article/details/81163975
今日推荐