Keep On Movin(HDU-5744)(优化过程)

Professor Zhang has kinds of characters and the quantity of the ii-th character is aiai. Professor Zhang wants to use all the characters build several palindromic strings. He also wants to maximize the length of the shortest palindromic string.

For example, there are 4 kinds of characters denoted as ‘a’, ‘b’, ‘c’, ‘d’ and the quantity of each character is {2,3,2,2}{2,3,2,2} . Professor Zhang can build {“acdbbbdca”}, {“abbba”, “cddc”}, {“aca”, “bbb”, “dcd”}, or {“acdbdca”, “bb”}. The first is the optimal solution where the length of the shortest palindromic string is 9.

Note that a string is called palindromic if it can be read the same way in either direction.
Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:

The first line contains an integer nn (1≤n≤105)(1≤n≤105) – the number of kinds of characters. The second line contains nn integers a1,a2,…,ana1,a2,…,an (0≤ai≤104)(0≤ai≤104).
Output
For each test case, output an integer denoting the answer.
Sample Input
4
4
1 1 2 4
3
2 2 2
5
1 1 1 1 1
5
1 1 2 2 3
Sample Output
3
6
1
3
这道题我花了很长的时间,自己做出来的,感触很深,真是思维决定编程。
逐步写我的思维流程
第一点的信息是如果给定所有的字符都是偶数个,那么这所有的字符都可以拼成一个完整的回文序,如果有一个奇数个的字符,我们也可以拼成一个完整的回文序。
后面我得出结论是如果奇数个的字符存在n种,那么如果要拼成回文那么至少要分成n个回文序,而这些奇数个的字符起码得是在各个回文串中的中间位置。
对于 1 1 2 2 3
那么我们就可以分成三个
我们先放好中间位置如:
1
1
3
剩下的怎么办,2和2
我们就去对称的去放到各个回文串中,
那我们从哪个回文串开始放?
题目说了只取回文集合中最小的那个,所以如果你从最大的开始放,是无法把整体值变大的,你必须把最小的回文串变大,这是关键,所以我们先放第一个
就变成
3
1
3
还剩下2个,这个在此寻找最小值,把他变大,这个个值是1
所以就变成
3
3
3了
所以答案就是3;
以这个思路的代码

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;


public class Main
{

    public static void main(String[]args)
    {
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        while((t--)>0)
        {
            int n=sc.nextInt();
            int count=0;
            ArrayList<Integer> list=new ArrayList<>(); //存奇数个的字符串的个数
            for(int i=0;i<n;i++)
            {
                int x=sc.nextInt();
                if(x%2==1)
                    list.add(x);//如果是奇数就放入
                else
                    count+=x;//所以的偶数个的字符我们可以看做一个整体都加起来
            }
            if(list.size()==0)
            {
                System.out.println(count);
                continue;//没有奇数的字符的情况
            }
            if(list.size()==1)//只有一个奇数的情况
            {
                System.out.println(list.get(0)+count);
                continue;
            }
            Collections.sort(list);//吧奇数从小到大
            int min=list.get(0);此时值最小的当然是第一个    
            while(count>0)
            {
                int i=0;
                for(i=0;i<list.size();i++)
                {
                    if(list.get(i)!=min)
                        break;//我们找有多少个奇数相同的字符
                }
                if(count>=i*2)//如果这些都可以填满
                {
                    for(int j=0;j<i;j++)
                        list.set(j, list.get(j)+2);//我们就去更新加2
                    count-=i*2;//然后减去
                }
                else如果剩下的count不能把所有最小的字符都加入,说明还有最小的剩余,所有答案就只能是这个min了
                {
                    break;
                }
                min=list.get(0);//更新最小值
            }
            System.out.println(min);
        }
    }
}

但是很遗憾超时了,可以猜测一定是min值更新的效率太低了,因为每次就加2

我们在想一想,如果是 1 1 1 2 2 2这种情况怎么样
那么就是首先
1
1
1至少分成三个
我们发现
一开始三个都是一个,那我们就不用2个2个去加,可以去2*3的个数去加,这样效率大大增加,也就是count=2+2+2,然后直接count/3,就是能加的个数,计算时间直接变成常数时间,
关键是并不是所有的都是一样的奇数,那我们就转化成一样的,其实后来发现 1 1 1 2 2 2和 1 1 2 2 3的答案是一样的,因为我们可以吧3拆成2+1,这个就是关键的关键
优化:

import java.util.Scanner;


public class Main 
{

    public static void main(String[]args)
    {
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        while((t--)>0)
        {
            int n=sc.nextInt();
            int num=0;//记录有多少个1
            int count=0;记录有多少个2
            for(int i=0;i<n;i++)
            {
                int x=sc.nextInt();
                if(x%2==0)//直接偶数就加
                    count+=x/2;
                else
                {//奇数的话就拆成1+偶数
                    num++;//递增
                    count+=x/2;//整数除
                }
            }
            if(num==0)//判断有没有奇数的
            {
                System.out.println(count*2);
            }
            else//如果有就对所以的回文整个整个的加
            {
                System.out.println(1+count/num*2);
            }
        }
    }
}

可见代码瞬间就简化,由此真正的感受到思维的程度决定了编程的复杂度
peace&love

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值