ural 1794. Masterpieces of World Architecture

链接: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;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PegasusWang_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值