Codeforces 8VC Venture Cup 2017 - Elimination Round D.PolandBall and Polygon

传送门:PolandBall and Polygon

题意:给定n条边的凸多边形,保证这种凸多边形任意三条对角线不会交于一点,然后从一顶点出发,每次走K步,然后将出发点与终点连接起来,输出此时多边形被分成的块数,重复此步骤n次。

解法:个人感觉就是多画几个图找规律。。或者你的几何学的好能推出公式或规律来,我发现的规律就是每画一条对角线,增加的块数等于该对角线跨过的对角线条数+1,也等于走的K步中去掉起点和终点经过的所有点发出的对角线的总和+1.这个规律感觉并不难找,重点是要想到能用树状数组去维护每个点发出的对角线的数量。剩下的就是稍稍模拟一下就好了。

坑点:注意当以上说的规律都是在k<=n/2的时候成立的,k>n/2时,需要将k=n-k,至于为什么,自己画个八边形模拟一下就明白了。

代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<map>
#define ll long long
#define pi acos(-1)
#define inf 0x3f3f3f3f
using namespace std;
typedef pair<int,int>P;
ll bit[1000005];
int n,k;
ll sum(int i)
{
	ll s=0;
	while(i>0)
	{
		s+=bit[i];
		i-=i&(-i);
	}
	return s;
}
void add(int i,int x)
{
	while(i<=n)
	{
		bit[i]+=x;
		i+=i&(-i);
	}
} 
int main()
{
	scanf("%d%d",&n,&k);
	int i=1;
	int t=n;
	ll ans=1;
	ll x=0;//x为每次新增的块数
	if(k>n/2)//坑点
	k=n-k;
	while(t--)
	{
		add(i,1);
		x=sum(i);
		i+=k;
		if(i>n)//如果i>n则x要分为两部分求
		{
			i-=n;
			x=(sum(n)-x)+sum(i-1);//注意树状数组求和统计的是闭区间[1,i]
			add(i,1);
		}
		else
		{
			x=sum(i-1)-x; 
			add(i,1);
		}
		ans+=x;
		ans++;//别忘了+1
		printf("%lld ",ans);
	 }
    return 0;
}

这题心路历程简直坎坷啊,由于我是赛后补题,所以开始前就看到这题有不到1000人过了,感觉应该不算难,不过费半天劲读明白题以后还是没有一个清晰地思路,我和队友说了题意,虽然某飞巨找到了点规律,但是我们并不明白他的意思。。直到20分钟过去,某宇巨也找到了规律,并发觉好像可以用树状数组搞一搞,就开始写,我研究了半天,在否定他人与自我否定中终于找也到了规律,翻书抄了树状数组代码(请自动忽略),这时候某宇巨交了一发,wa到6上,就开始怀疑是不是方法有问题,而我却不知为啥一直都是输出的最后一个数比正确答案少一个。。到最后终于发现是因为有个地方多减了一个数,还是某宇巨帮我DEBUG的,然而此时马上结束了,而某宇巨稍微搜了下题解发现了坑点顺利AC,在某宇巨的提醒下我成功绕过坑点却因为树状数组的sum函数没写long long类型wa在6上,紧赶慢赶没能在结束前A掉。与此同时前面提到的某飞巨还在不紧不慢的DEBUG他那线段树。。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值