题意:给定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他那线段树。。