8VC Venture Cup 2017 - Elimination Round D. PolandBall and Polygon 树状数组+思维 妙啊

题意:给你一个凸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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值