2016 Multi-University Training Contest 2----解题报告
1.1001 HDU 5734
我们就可以使用标准的一元二次方程求极值的方法来直接求,数据虽然多但是不会超过long long。
代码如下:
代码如下:
int main()
{
#ifdef LOCAL
///freopen("in.txt", "r", stdin);
///freopen("out.txt", "w", stdout);
#endif // LOCAL
int t, n;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
LL sum = 0;
LL sum2 = 0;
LL tmp;
for(int i = 0; i < n; ++i)
{
scanf("%I64d", &tmp);
sum += max(tmp, -tmp);
sum2 += tmp * tmp;
}
LL up = n * sum2 - sum * sum; //分子分母都有4 所以直接提前消去
LL down = n;
LL gcd = __gcd(up, down); //__gcd库函数
printf("%I64d/%I64d\n", up / gcd, down / gcd);
}
return 0;
}
2.1009 HDU 5742
这道题题干意思很明确就是在0-100之间选一些数字,构成一个和非零,且非递增的数组,然后使得 a1+a2∑ni=1ai 这个值最大,实际上就是(a[1]+a[2]) / (a[1] + .... + a[n])最大,我们把这个式子变个形式,也就是x / (x * y),要保证这个式子尽量大,只需要x足够的大,y足够的小,x只由a[1] 和 a[2]决定,所以这两个值要尽可能的取100,其余的a[3]到a[n]要尽可能的取最小值。
题干中还说了,已知一些数字,比如我们知道这个数组大小为5,已知的数字分别是_ _ 2 _ 1 那么这个数组的情况就是 100 100 2 1 1,再比如10 _ _ _ _ -> 10 10 0 0 0
具体在计算的时候就是首先考虑a[1]和a[2]的填法,如果a[1]是未知的直接使用100,如果a[2]是未知的直接使用a[1]的值,而不是100,剩余的数字从n开始往前扫描,一开始把填的数字固定为0,遇到未知情况,就把这个数字填上,否则将这个需要填的数字变为和当前值一样的值,比如100 100 _ _ 3 _ _ 2 _ _这种,首先填上0 碰到2以后开始填2,碰到3以后填3,也就是100 100 3 3 3 2 2 20 0
代码如下:
const int maxn = 105;
int num[maxn];
int main()
{
#ifdef LOCAL
///freopen("in.txt", "r", stdin);
///freopen("out.txt", "w", stdout);
#endif // LOCAL
int t;
int n, m, x, y;
cin >> t;
while(t--)
{
memset(num, -1, sizeof(num));
cin >> n >> m;
for(int i = 0; i < m; ++i)
{
cin >> x >> y;
num[x] = y;
}
if(num[1] == -1)
num[1] = 100;
if(num[2] == -1)
num[2] = num[1];
int k = 0;
for(int i = n; i >= 3; --i)
{
if(num[i] == -1)
num[i] = k;
else
k = num[i];
}
int sum1 = num[1] + num[2];
int sum2 = 0;
for(int i = 1; i <= n; ++i)
sum2 += num[i];
int d = __gcd(sum1, sum2);
cout << sum1 / d << "/" << sum2/d <<endl;
}
return 0;
}
3.1011 HDU 5744
这道题题目的意思就是说给你一堆字符你要把他们分成很多组回文串(每组必须 使用所有的字符有且仅有一次),从每个组中选出最短回文串的长度,然后输出这些组的最短回文串的长度的最大值。我们假设现在是偶数,那么很明显答案就是这个组的字符总个数,麻烦的是含有奇数的情况,实际上考虑到要是最短回文串的最长,也就是说要分的平均,为什么这么说呢。假设每个组是10个字符,要求必须分成两个回文串,那么和明显5和5 这种情况是最小最大的。所以我们把奇数单独抽出来,然后把刚刚的偶数,平均分配给这些奇数,另外对于一个奇数来说,我们需要把它拆分为1+k两部分,k作为一个偶数,继续算入刚刚的偶数。
假设odd记录奇数个数,sum记录偶数的个数( 包括从奇数中拆分出来的k),如果odd为0,答案就是sum,否则需要考虑sum/odd = x, 如果x为偶数,那么加上奇数串长度1,答案就是x + 1, 否则就应该是x - 1 + 1,即x本身。
例如:
1 1 4 4 4 odd = 2,sum = 12, x = 6,也就是每个1可以得到6个字符,那么结果就是6 + 1,即x + 1
1 1 2 2 2 odd = 2,sum = 6, x = 3,两个1,一个可以得到2,一个可以得到4,但是结果很明显是3,也就是x - 1 + 1,因为 奇数和奇数,是不可能构成回文的
代码如下:
int main()
{
#ifdef LOCAL
///freopen("in.txt", "r", stdin);
///freopen("out.txt", "w", stdout);
#endif // LOCAL
int t, n;
cin >> t;
while(t--)
{
cin >> n;
int odd = 0;
int sum = 0;
int a;
for(int i = 0; i < n; ++i)
{
cin >> a;
if(a & 1)
{
odd++;
sum += a - 1;
}
else
sum += a;
}
if(odd == 0)
{
cout << sum << endl;
}
else
{
if((sum / odd) & 1)
cout << sum / odd << endl;
else
cout << sum / odd + 1 << endl;
}
}
return 0;
}