题意:给你一个凸N边形,然后一个K,每次从1到1+k连线,然后下一次1+k到1+k+k,依次这样连线,直到最后有重复的线出现,问每次新连一条线可以将该N边形分成几块。
题解:由于GCD(n,k)=1,所以肯定可以连N次,关键是连边产生的规则,自己可以手动模拟一下, 可以得出一个结论,现在的块数=原来的块数+现在新连线与以前的线交线个数+1;那么每个点的使用次数我们就可以用一个树状数组来存,每次查询的时候都是在(1,1+k)这个开区间那么我们就可以计算【2-k】这个区间的的点的数量,开始的时候我们每次都处理 update(i,1) 和update(i+k,1), 注意要小心 当划线超过N的时候 ,也就是i+k>n,我们应该 (i+k)%n,这时候应该 querry(n)-querry(i)+querry((i+k)%n-1)+1, 其他时候就是querry(i+k-1)-querry(i);
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define fio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mse(a,b) memset(a,b,sizeof a)
#define pb push_back
using namespace std;
const int mod=1e9+7;
const int maxx=1e6+10;
using namespace std;
const long double PI = 3.14159265358979323846;
#define fio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
inline int read()
{ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) { x=x*10+ch-48; ch=getchar(); } return x*f;}
ll ans[maxx];
ll dou[maxx];
ll n,k;
ll vis[maxx];
ll tree[maxx];
ll lowbit(int x) {return x&-x;}
ll update(int x,int val)
{
while(x<=n)
{
tree[x]+=val;
x+=lowbit(x);
}
}
ll sum(int x)
{
ll res=0;
while(x)
{
res+=tree[x];
x-=lowbit(x);
}
return res;
}
signed main()
{
fio;
cin>>n>>k;
k=min(k,n-k);
update(1,1);
int cnt=1;
dou[cnt++]=2;
ll ous=2;
int now=1+k;
update(now,1);
for(int i=1;i<n;i++)
{
int pre=now;
now+=k;
if(now > n) now-=n;
if(now>pre) ous+=sum(now-1)-sum(pre)+1;
else ous+=sum(n)-sum(pre)+sum(now-1)+1;
dou[cnt++]=ous;
update(pre,1);
update(now,1);
}
for(int i=1;i<=n;i++)
{
cout<<dou[i]<<" ";//<<endl;
}
// system("pause");
return 0;
}