bzoj4201 多边形序列

题目大意

参见截图
题面截图

题解

之前做过一道名为电路图的神题,所以很快就发现了几个有用的结论:

  • L的数量-R的数量=4.
  • 一个序列满足题意当且仅当序列中不存在两个相邻的R,即所有的R都是分开的.
  • 首尾的两个字符不能同时为R,因为在环上,首尾是相邻的.

利用插空法,可以得出公式:

ans=C5n2+3C5n2+1

不妨令 t=n2 ,为了避免讨论t+1,t+3与5的大小关系,我们对式子做进一步化简:
ans=C5t+3C5t+1=t2(t+1)(t1)12

然后写个高精度就行了。
乘法部分,我不太会写压位,就用的 NTT.
结构体中数组开大了会崩溃,扩个栈就好了(具体原理我不清楚).

参考代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 550000
const int G=998244353,g=3;
int exp(int a,int k)
{
    int an=1;
    for(;k;k>>=1)
    {
        if(k&1)
        {
            an=1ll*an*a%G;
        }
        a=1ll*a*a%G;
    }
    return an;
}
int A[MAXN<<1],B[MAXN<<1],N,W[MAXN<<1];
void NTT(int X[],int nn,int ty)
{
    int i,j,k,m,t1,t2;
    for(i=0;i<nn;i++)
    {
        for(j=0,k=i,m=1;m<nn;m<<=1,j=(j<<1)|(k&1),k>>=1);
        if(i<j)
        {
            t1=X[i];
            X[i]=X[j];
            X[j]=t1;
        }
    }
    W[0]=1;
    for(m=1;m<nn;m<<=1)
    {
        t1=exp(g,G-1+ty*(G-1)/(m<<1));
        for(i=1;i<m;i++)
        {
            W[i]=1ll*W[i-1]*t1%G;
        }
        for(k=0;k<nn;k+=m<<1)
        {
            for(i=k;i<k+m;i++)
            {
                t1=X[i];
                t2=1ll*X[i+m]*W[i-k]%G;
                X[i]=t1+t2;
                X[i]-=X[i]>=G?G:0;
                X[i+m]=t1-t2;
                X[i+m]+=X[i+m]<0?G:0;
            }
        }
    }
    if(ty==1)
    {
        return ;
    }
    t1=exp(nn,G-2);
    for(i=0;i<nn;i++)
    {
        X[i]=1ll*X[i]*t1%G;
    }
    return ;
}
struct big
{
    int x[MAXN],len;
    big()
    {
        memset(x,0,sizeof(x)); 
        len=0;
    }
    big operator = (char* s)
    {
        len=strlen(s);
        for(int i=1;i<=len;i++)
        {
            x[i]=s[len-i]-'0';
        }
        return *this;
    }
    big operator = (int num)
    {
        char s[MAXN];
        sprintf(s,"%d",num);
        return *this=s;
    }
    big operator + (big& b)
    {
        big c=big();
        c.len=max(len,b.len);
        for(int i=1;i<=c.len;i++)
        {
            c.x[i]+=x[i]+b.x[i];
            if(c.x[i]>9)
            {
                c.x[i+1]++;
                c.x[i]-=10;
            }
        }
        for(;c.x[c.len+1];c.len++);
        return c;
    }
    big operator - (big& b)
    {
        big c=big();
        c.len=len;
        for(int i=1;i<=c.len;i++)
        {
            c.x[i]+=x[i]-b.x[i];
            if(c.x[i]<0)
            {
                c.x[i+1]--;
                c.x[i]+=10;
            }
        }
        for(;c.len>1&&!c.x[c.len];c.len--);
        return c;
    }
    big operator / (int num)
    {
        big c=big();
        int p=0,q=0;
        c.len=len;
        for(int i=c.len;i>=1;i--)
        {
            p=10*q+x[i];
            c.x[i]=p/num;
            q=p%num;
        }
        for(;c.len>1&&!c.x[c.len];c.len--);
        return c;
    }
    void print()
    {
        for(int i=len;i>=1;i--)
        {
            putchar('0'+x[i]);
        }
        return ;
    }
    bool mod_2()
    {
        return x[1]&1;
    }
    big operator * (big& b)
    {
        memset(A,0,sizeof(A));
        memset(B,0,sizeof(B));
        big c=big();
        c.len=len+b.len;
        for(N=1;N<=c.len;N<<=1);
        for(int i=1;i<=len;i++)
        {
            A[i-1]=x[i];
        }
        for(int i=1;i<=b.len;i++)
        {
            B[i-1]=b.x[i];
        }
        NTT(A,N,1);
        NTT(B,N,1);
        for(int i=0;i<N;i++)
        {
            A[i]=1ll*A[i]*B[i]%G;
        }
        NTT(A,N,-1);
        for(int i=0;i<N;i++)
        {
            c.x[i+1]=A[i]%10;
            A[i+1]+=A[i]/10;
        }
        for(;c.len>1&&!c.x[c.len];--c.len);
        return c;
    }
};
char s[MAXN];
int main_main()
{
    freopen("A.out","w",stdout);
    big x=big(),a=big(),b=big(),c=big();
    c=1;
    scanf("%s",s);
    x=s;
    if(x.mod_2())
    {
        printf("0");
        return 0;
    }
    x=x/2;
    a=x+c;
    b=x-c;
    x=x*x;
    x=x*a;
    x=x*b;
    x=x/12;
    x.print();
    return 0;
}
const int main_stack=16; 
char my_stack[128<<20]; 
int main() { 
  __asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory"); 
  __asm__("movl %%eax, %%esp;\n"::"a"(my_stack+sizeof(my_stack)-main_stack):"%esp"); 
  main_main(); 
  __asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp"); 
  return 0; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值