[数论] 2017 计蒜之道 初赛 第一场 阿里天池的新任务

我们令子串 Ss,t 对应的 ws 为这个子串的 b
因为互质 所以b是互不相同的 转为求有几个 b 满足条件
然后每一位看作一个限制 把所有限制离散化取交即可 注意处理奇偶性
还有一个细节 snm+1 我们还要倒着把最后 m1 b <script type="math/tex" id="MathJax-Element-280">b</script>中合法的减掉

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
typedef long long ll;

const int N=1000005;

int n,a,b,L,R;
int m; char t[N];

int tot;
int l[N<<2],r[N<<2]; bool e[N<<2];

inline void add(ll _L,ll _R,ll ax,int t){
  if (_L>_R) return;
  ll L=(_L+n-ax%n)%n,R=(_R+n-ax%n)%n;
  if (L<=R){
    l[++tot]=L,r[tot]=R;
    e[tot]=t^((L&1)^(_L&1));
  }else{
    l[++tot]=0,r[tot]=R;
    e[tot]=t^((R&1)^(_R&1));
    l[++tot]=L,r[tot]=n-1;
    e[tot]=t^((L&1)^(_L&1));
  }
}

int sx[N<<3],icnt;
int idx[N<<3],cnt;
int T[N<<3][2];

inline bool cmp(int x,int y){
  return (x>0?l[x]:r[-x])<(y>0?l[y]:r[-y]);
}

inline int calc(int l,int r,int t){
  if (t==1){
    if (~l&1) l++;
    if (r&1) r++;
    return (r-l+1)>>1;
  }else{
    if (l&1) l++;
    if (~r&1) r++;
    return (r-l+1)>>1;
  }
}

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  scanf("%d%d%d%d%d",&n,&a,&b,&L,&R);
  scanf("%s",t+1); m=strlen(t+1);
  for (int i=1;i<=m;i++)
    if (t[i]=='A'){
      add(L,R,(ll)a*(i-1)%n,0);
    }else if (t[i]=='T'){
      add(L,R,(ll)a*(i-1)%n,1);
    }
    else if (t[i]=='G'){
      add(0,L-1,(ll)a*(i-1)%n,0);
      add(R+1,n-1,(ll)a*(i-1)%n,0);
    }else if (t[i]=='C'){
      add(0,L-1,(ll)a*(i-1)%n,1);
      add(R+1,n-1,(ll)a*(i-1)%n,1);
    }
  sx[++icnt]=0; sx[++icnt]=n;
  for (int i=1;i<=tot;i++){
    sx[++icnt]=l[i],sx[++icnt]=r[i]+1;
  }
  sort(sx+1,sx+icnt+1); icnt=unique(sx+1,sx+icnt+1)-sx-1;
  for (int i=1;i<=tot;i++){
    l[i]=lower_bound(sx+1,sx+icnt+1,l[i])-sx;
    r[i]=lower_bound(sx+1,sx+icnt+1,r[i]+1)-sx;
    idx[++cnt]=i,idx[++cnt]=-i;
  }
  sort(idx+1,idx+cnt+1,cmp);
  ll t[2]={0,0}; int pnt=1;
  ll ans=0;
  for (int i=1;i<icnt;i++){
    while (pnt<=cnt && (idx[pnt]>0?l[idx[pnt]]:r[-idx[pnt]])==i)
      if (idx[pnt]>0)
    t[e[idx[pnt]]]++,pnt++;
      else
    t[e[-idx[pnt]]]--,pnt++;
    T[i][0]=t[0]; T[i][1]=t[1];
    if (t[0]==m)
      ans+=calc(sx[i],sx[i+1]-1,0);
    if (t[1]==m)
      ans+=calc(sx[i],sx[i+1]-1,1);
  }
  for (int i=1;i<m;i++){
    b=(b+n-a)%n;
    int it=upper_bound(sx+1,sx+icnt+1,b)-sx-1;
    if (T[it][b&1]==m)
      ans--;
  }
  printf("%lld\n",ans);
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值