链接:http://acm.timus.ru/problem.aspx?space=1&num=1794
描述:一个班上有n个人要发言,他们排成一个圈并且按照顺时针顺序一个一个依次演讲,有一些学生想要先发言,而有一些学生想要后发言。现在告诉你每个人想第几发言,问谁第一发言最好,能尽量更多满足每个人的要求(即满足他想要的发言次序)。要有多种答案,输出其中一个。
input: n个学生和第 i 个学生期望的发言次序
output: 第一个发言的人的编号
思路:思路就是一开始没思路。晕+。切入正题:首先注意这个条件“排成一个圈并且按照顺时针顺序一个一个依次演讲”,然后找规律吧,看了讨论有人用的是什么voting(投票)
举个例子:
4
4 1 2 3
1 4 3 2
4 2 -> 3 1 -> 2 4 -> 1 3
3 2 1 4
按照顺时针方向旋转,第一个学生(假设编号用 i 表示 i = 1,期望次序 a[i] = 4), 顺时针旋转三次后才能得到,此时第一个位置变成了 2, 也就是说,要是想要满足第一个学生的期望条件,就需要2号成为第一个演讲的。同理,学生i = 2,期望次序a[2] = 1想要称为第一个演讲的,旋转三次后成为一号元素。也就是说,对于i和a[i],要是满足第i个学生的a[i],需要将第 (i - a[i] + 1+n) % n个元素挪到第一个位置。后面的+n,保证非负数取模也为整数,特例是当 i - a[i] + 1+n = n时,结果为0,需要赋值为n。还有一种方法就是处理上的一点技巧,直接用公式++count[((i - a[i] + 1) % N + N) % N]
i a[i] (i - a[i] + n + 1) % n
1 4 2
2 1 2
3 2 2
4 3 2
这个巧了,要是满足让 i 在第a[i]个位置,都需要把2移到第一个位置。所以2就是答案。对于其他情况,一样的算,只需要统计出来一个编号,满足最多的需要把它放在第一个位置,就输出这个编号。
代码:
//g++ 4.7.2 提交
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int main()
{
int n;
scanf("%d", &n);
int a[n+1], count[n+1];
memset(count, 0, sizeof(count));
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i)
{
int t = (i-a[i]+n+1)%n; //for循环里可以直接++count[((i - a[i] + 1) % N + N) % N]
if (t == 0)
t = n;
++count[t];
}
int maxnum = 0, maxindex;
for (int i = 1; i <= n; ++i)
if (count[i] > maxnum)
{
maxnum = count[i];
maxindex = i;
}
printf("%d\n", maxindex);
return 0;
}