[ACM] ZOJ 3844 Easy Task (模拟+哈希)

Easy Task

Time Limit: 2 Seconds       Memory Limit: 65536 KB

You are given n integers. Your task is very easy. You should find the maximum integer a and the minimum integer b among these n integers. And then you should replace both a and bwith a-b. Your task will not be finished unless all the integers are equal.

Now the problem come, you want to know whether you can finish you task. And if you can finish the task, you want to know the final result.

Input

The first line of the input contain an integer T(T≤ 20) indicates the number of test cases.

Then T cases come. Each case consists of two lines. The first line is an integer n(2≤ n≤ 10) as the problem described. The second line contains n integers, all of them are no less than -100000 and no more than 100000.

Output

For each case you should print one line. If you can finish your task, you should print one of the n integers. Otherwise, you should print "Nooooooo!"(without quotes).

Sample Input
2
3
1 2 3
2
5 5
Sample Output
2
5

Author:  CHEN, Zemin
Source:  ZOJ Monthly, January 2015

解题思路:

题意为给定n个数(2<=n<=10),每个数的范围为 -100000到100000,有一种操作:找到这n个数中最大的数max,最小的数min,把这两个数都替换为 max-min , 重复这样的操作,直到这n个数完全相同,如果可以达到这样的目的,就输出最后那n个数中的其中一个(每个数都一样),如果不能,则输出 Nooooooo!。

n的范围很小,直接按照题意排序模拟即可,一开始觉得任何数据都可以达到目的,没有输出Nooooooo!的情况,写了一发,交上去,果断WA.后来和二师兄讨论,应该记录状态才对,一旦出现相同的状态,那么就不能达到目的,输出Nooooooo!。方法为哈希查找,每一个状态用包含这n个数的结构体来保存,关键字是这n个数的和,以n个数的和对一个大素取余作为关键字,10个数的最大和不超过100000*10,所以开辟这么大的结构体类型的vector数组,当出现一个新的状态时,就去该状态的和取余后的索引中的那些状态去比较,这样可以减少比较次数,因为一个状态和另一个状态相同,它们分别的元素之和取余后相等是大前提。

注意:n个元素和可能是负数,建立索引要加上mod变为正数.

代码:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <cmath>
#include <iomanip>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <cctype>
using namespace std;
#define ll long long
const int mod=100000*10+1;
const int inf=0x3f3f3f3f;
const int maxn=12;
int num[maxn];
int n;
struct Node
{
    int a[maxn];
};
vector<Node>vc[mod+10];

int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        for(int i=0;i<=mod;i++)
            vc[i].clear();
        Node tp;
        cin>>n;
        int sum=0;
        for(int i=0;i<n;i++)
        {
            cin>>num[i];
            sum+=num[i];
        }
        tp.a[n]=sum;
        sort(num,num+n);
        if(num[0]==num[n-1])
        {
            cout<<num[0]<<endl;
            continue;
        }
        for(int i=0;i<n;i++)
            tp.a[i]=num[i];
        vc[(tp.a[n]+mod)%mod].push_back(tp);
        int ans=inf;
        while(1)
        {
            int cha=num[n-1]-num[0];
            sum=sum-num[n-1]-num[0]+2*cha;//新的sum
            num[0]=cha,num[n-1]=cha;
            sort(num,num+n);
            if(num[0]==num[n-1])
            {
                ans=num[0];
                break;
            }
            tp.a[n]=sum;
            for(int i=0;i<n;i++)
                tp.a[i]=num[i];
            bool ok=0;
            int idx=(tp.a[n]+mod)%mod;//去相应的索引中去找看是否有相同的状态
            for(int i=0;i<vc[idx].size();i++)
            {
                    int j;
                    for(j=0;j<n;j++)
                    {
                        if(tp.a[j]!=vc[idx][i].a[j])
                            break;
                    }
                    if(j==n)
                    {
                        ok=1;//找到了!
                        break;
                    }
            }
            if(ok==1)
                break;
            vc[idx].push_back(tp);
        }
        if(ans!=inf)
            cout<<ans<<endl;
        else
            cout<<"Nooooooo!"<<endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值