BJOI2018简要题解

R1T1二进制

发现一个二进制中的\(1\)对这个数模\(3\)的结果有\(1\)\(2\)的贡献

所以当序列有偶数个\(1\)时,重排后就珂以

当序列里有奇数个\(1\)且个数不为\(1\),有至少\(2\)\(0\)时,重排后就珂以

我们考虑用总数减去不合法的得出答案

首先,根据上面的结论,我们每次珂以线性得出答案,但是只有\(50pts\)

考虑动态dp,线段树维护

每个节点维护\(dl[0/1][0/1]\),表示左边一段连续区间中有\(0/1\)\(0\)\(1\)个数的奇偶性为\(0/1\)的个数,类似的维护\(dr\)

还要维护\(fl[0/1/2]\),表示左边一段连续取件有\(0/1/2\)\(0\)\(1\)\(1\)的个数,类似的维护\(fr\)

转移显然,这样我们就得到了一个\(O((n+m)\log n)\)的做法

#include <bits/stdc++.h>
#define ll long long
#define N 100005
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register ll x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
struct data{
    ll dl[2][2],dr[2][2],fl[3],fr[3],s;
    int l0,r0,s0,s1;
    inline void init()
    {
        dl[0][0]=dl[0][1]=dl[1][0]=dl[1][1]=dr[0][0]=dr[0][1]=dr[1][0]=dr[1][1]=0;
        fl[0]=fl[1]=fl[2]=fr[0]=fr[1]=fr[2]=0;
        l0=r0=s0=s1=s=0;
    }
    inline void pre(register int x)
    {
        init();
        if(x)
            dl[0][1]=dr[0][1]=s1=s=fl[0]=fr[0]=1;
        else
            dl[1][0]=dr[1][0]=s0=l0=r0=1;
    }
}tr[N<<2];
int n,a[N],m;
inline data pushup(register data A,register data B)
{
    data c;
    c.init();
    for(register int i=0;i<=1;++i)
        for(register int j=0;j<=1;++j)
        {
            c.dl[i][j]+=A.dl[i][j];
            c.dr[i][j]+=B.dr[i][j];
            if(i>=A.s0)
                c.dl[i][j]+=B.dl[i-A.s0][j^(A.s1&1)];
            if(i>=B.s0)
                c.dr[i][j]+=A.dr[i-B.s0][j^(B.s1&1)];
        }
    for(register int i=0;i<=2;++i)
    {
        c.fl[i]+=A.fl[i];
        c.fr[i]+=B.fr[i];
        if(!A.s1)
            c.fl[min(2,i+A.s0)]+=B.fl[i];
        if(!B.s1)
            c.fr[min(2,i+B.s0)]+=A.fr[i];
    }
    if(A.s1==1&&B.l0)
        ++c.fl[min(2,A.s0+B.l0)],c.fl[2]+=B.l0-1;
    if(B.s1==1&&A.r0)
        ++c.fr[min(2,B.s0+A.r0)],c.fr[2]+=A.r0-1;
    c.l0=(A.s1==0)?A.s0+B.l0:A.l0;
    c.r0=(B.s1==0)?B.s0+A.r0:B.r0;
    c.s0=A.s0+B.s0;
    c.s1=A.s1+B.s1;
    c.s=A.s+B.s;
    c.s+=A.dr[0][0]*(B.dl[0][1]+B.dl[1][1]);
    c.s+=A.dr[0][1]*(B.dl[0][0]+B.dl[1][0]);
    c.s+=A.dr[1][0]*B.dl[0][1];
    c.s+=A.dr[1][1]*B.dl[0][0];
    if(B.l0)
        c.s+=B.l0*(A.fr[0]+A.fr[1]+A.fr[2])-A.fr[0];
    if(A.r0)
        c.s+=A.r0*(B.fl[0]+B.fl[1]+B.fl[2])-B.fl[0];
    return c;
}
inline void build(register int x,register int l,register int r)
{
    if(l==r)
    {
        tr[x].pre(a[l]);
        return;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    tr[x]=pushup(tr[x<<1],tr[x<<1|1]);
}
inline void modify(register int x,register int l,register int r,register int pos)
{
    if(l==r)
    {
        tr[x].pre(a[l]);
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid)
        modify(x<<1,l,mid,pos);
    else
        modify(x<<1|1,mid+1,r,pos);
    tr[x]=pushup(tr[x<<1],tr[x<<1|1]);
}
inline data query(register int x,register int l,register int r,register int L,register int R)
{
    if(L<=l&&r<=R)
        return tr[x];
    int mid=l+r>>1;
    if(R<=mid)
        return query(x<<1,l,mid,L,R);
    else if(L>mid)
        return query(x<<1|1,mid+1,r,L,R);
    else
        return pushup(query(x<<1,l,mid,L,R),query(x<<1|1,mid+1,r,L,R));
}
int main()
{
    n=read();
    for(register int i=1;i<=n;++i)
        a[i]=read();
    build(1,1,n);
    m=read();
    while(m--)
    {
        int opt=read();
        if(opt==1)
        {
            int pos=read();
            a[pos]^=1;
            modify(1,1,n,pos);
        }
        else
        {
            int l=read(),r=read();
            write(1ll*(r-l+1)*(r-l+2)/2-query(1,1,n,l,r).s),puts("");
        }
    }
	return 0;
}

R1T2染色

神仙结论题

对于每个联通块分别考虑

首先,有奇环肯定不行

边数大于\(n+1\)肯定不行,至少有三个环

边数小于等于\(n\)的一定珂以

边数等于\(n+1\)的要拓扑排序特判一下

证明

#include <bits/stdc++.h>
#define N 20005
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
struct node{
    int to,nxt;
}e[N<<1];
int head[N>>1],cnt=0,du[N>>1];
inline void add(register int u,register int v)
{
    e[++cnt]=(node){v,head[u]};
    head[u]=cnt;
}
int T,n,m,col[N>>1],f,vtot,etot;
vector <int> pt;
queue <int> q;
inline void dfs(register int x,register int cl)
{
    if(f)
        return;
    if(col[x]!=-1)
    {
        if(col[x]!=cl)
            f=1;
        return;
    }
    col[x]=cl,++vtot,pt.push_back(x);
    for(register int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        ++etot;
        dfs(v,cl^1);
    }
}
int main()
{
    T=read();
    while(T--)
    {
        cnt=f=0;
        memset(head,0,sizeof(head));
        memset(du,0,sizeof(du));
        memset(col,-1,sizeof(col));
        n=read(),m=read();
        for(register int i=1;i<=m;++i)
        {
            int u=read(),v=read();
            add(u,v),add(v,u);
            ++du[u],++du[v];
        }
        for(register int i=1;i<=n;++i)
            if(col[i]==-1)
            {
                vtot=etot=0;
                pt.clear();
                dfs(i,0);
                if(f)
                    break;
                if(etot/2>vtot+1)
                {
                    f=1;
                    break;
                }
                if(etot/2<=vtot)
                    continue;
                for(register int j=0;j<pt.size();++j)
                    if(du[pt[j]]==1)
                        q.push(pt[j]);
                while(!q.empty())
                {
                    int u=q.front();
                    q.pop();
                    for(register int j=head[u];j;j=e[j].nxt)
                    {
                        int v=e[j].to;
                        if(--du[v]==1)
                            q.push(v);
                    }
                }
                int tot=0;
                for(register int j=0;j<pt.size();++j)
                    if(du[pt[j]]==2)
                    {
                        int tmp=0;
                        for(register int k=head[pt[j]];k;k=e[k].nxt)
                            if(du[e[k].to]==3)
                                ++tmp;
                        if(tmp==2)
                            ++tot;
                    }
                if(tot<2)
                {
                    f=1;
                    break;
                }
            }
            puts(f?"NO":"YES");
    }
	return 0;
}

R1T3求和

观察到\(k\)的值域很小是\([1,50]\),我们可以暴力预处理,并做个前缀和,查询树上差分即可,复杂度\(O(50n+m \log n)\)

#include <bits/stdc++.h>
#define mod 998244353
#define N 300005
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
struct node{
    int to,nxt;
}e[N<<1];
int head[N],cnt;
inline void add(register int u,register int v)
{
    e[++cnt]=(node){v,head[u]};
    head[u]=cnt;
}
int n,m,f[N][51],dep[N],siz[N],son[N],fa[N],top[N];
inline void dfs1(register int x,register int fat)
{
    siz[x]=1;
    for(register int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fat)
            continue;
        dep[v]=dep[x]+1;
        for(register int j=1,t=dep[v];j<=50;++j,t=1ll*t*dep[v]%mod)
            f[v][j]=(0ll+f[x][j]+t)%mod;
        dfs1(v,x);
        fa[v]=x;
        siz[x]+=siz[v];
        if(siz[v]>siz[son[x]])
            son[x]=v;
    }
}
inline void dfs2(register int x,register int t)
{
    top[x]=t;
    if(son[x])
        dfs2(son[x],t);
    for(register int i=head[x];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fa[x]||v==son[x])
            continue;
        dfs2(v,v);
    }
}
inline int getlca(register int x,register int y)
{
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy])
            swap(fx,fy),swap(x,y);
        x=fa[fx];
        fx=top[x];
    }
    return dep[x]<dep[y]?x:y;
}
int main()
{
    n=read();
    for(register int i=1;i<n;++i)
    {
        int u=read(),v=read();
        add(u,v),add(v,u);
    }
    dfs1(1,0);
    dfs2(1,1);
    int m=read();
    while(m--)
    {
        int u=read(),v=read(),k=read();
        int lca=getlca(u,v);
        write((0ll+f[u][k]+f[v][k]-f[lca][k]-f[fa[lca]][k]+2ll*mod)%mod),puts("");
    }
	return 0;
}

R2T1双人猜数游戏

神仙提答

\(f_{x,y,k}\)表示\(x,y\)两个数,进行\(k\)轮,是否已经确定,暴力转移即可

#include <bits/stdc++.h>
#define N 300
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
int s,t;
char c;
int f[N+1][N+1][20];
inline int calc1(register int x,register int y,register int k)
{
    int num=x*y,up=sqrt(x*y),xx=0,yy=0,cnt=0;
    for(register int i=s;i<=up;++i)
        if(num%i==0&&(!k||!f[i][num/i][k-1]))
            xx=i,yy=num/i,++cnt;
    return cnt==1&&xx==x&&yy==y;
}
inline int calc2(register int x,register int y,register int k)
{
    int num=x+y,up=x+y>>1,xx=0,yy=0,cnt=0;
    for(register int i=s;i<=up;++i)
        if(!k||!f[i][num-i][k-1])
            xx=i,yy=num-i,++cnt;
    return cnt==1&&xx==x&&yy==y;
}
inline int calc3(register int x,register int y)
{
    int num=x*y,up=sqrt(x*y),xx=0,yy=0,cnt=0;
    for(register int i=s;i<=up;++i)
        if(num%i==0&&f[i][num/i][t]&&(t<2||!f[i][num/i][t-2]))
            xx=i,yy=num/i,++cnt;
    return cnt==1&&xx==x&&yy==y;
}
inline int calc4(register int x,register int y)
{
    int num=x+y,up=x+y>>1,xx=0,yy=0,cnt=0;
    for(register int i=s;i<=up;++i)
        if(f[i][num-i][t]&&(t<2||!f[i][num-i][t-2]))
            xx=i,yy=num-i,++cnt;
    return cnt==1&&xx==x&&yy==y;
}
inline void Work(register int x,register int y)
{
    if(!f[x][y][t])
        return;
    for(register int k=0;k<t;++k)
        if(f[x][y][k])
            return;
    int nw=((t&1)&&c=='A')||(!(t&1)&&c=='B');
    int fl=nw?calc3(x,y):calc4(x,y);
    if(fl)
        write(x),putchar(' '),write(y),exit(0);
}
int main()
{
    s=read();
    c=getchar();
    while(c!='A'&&c!='B')
        c=getchar();
    t=read();
    for(register int k=0,nw=c=='A';k<=t;++k,nw^=1)
        for(register int i=s;i<=N;++i)
            for(register int j=i;j<=N;++j)
            {
                if(k>1)
                    f[i][j][k]=f[i][j][k-2];
                f[i][j][k]|=nw?calc1(i,j,k):calc2(i,j,k);
            }
    for(register int sum=s<<1;;++sum)
        for(register int i=s;i<=sum>>1;++i)
            Work(i,sum-i);
	return 0;
}

R2T2链上二次求和

因为是一条链,所以我们可以放到区间上去看(注意:因为是链,所以修改/查询的区间有可能会出现\(l>r\)的情况)

\(S\)为数列的前缀和,\(SS\)\(S\)的前缀和

\[\sum_{i=l}^{r} \sum_{j=i}^{n}\left(S_{j}-S_{j-i}\right)=\sum_{i=l}^{r}\left(\sum_{j=i}^{n} S_{j}-\sum_{j=0}^{n-i} S_{j}\right)=\sum_{i=l}^{r}\left(S S_{n}-S S_{i-1}-S S_{n-i}\right) \]

这个珂以用线段树维护

对于每个修改操作,我们要考虑对SS每个位置的贡献

  • \(l \leq i \leq r , \frac{(i-l+1)(i-l+2)v}{2}\)

  • \(r<i , (\frac{(r-l+1)(r-l+2)}{2}+(i-r)(r-l+1))v\)

线段树上维护二次函数区间加即可,复杂度为\(O((n+m)\log n)\)

#include <bits/stdc++.h>
#define mod 1000000007
#define N 200005
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline void add(register int &x,register int y)
{
    x+=y;
    if(x>=mod)
        x-=mod;
}
const int inv2=500000004,inv6=166666668;
int n,m;
int a[N<<3],b[N<<3],c[N<<3],t[N<<3];
inline int S(register int n)
{
    return 1ll*n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
}
inline void put(register int x,register int l,register int r,register int A,register int B,register int C)
{
    int s0=r-l+1,s1=1ll*(l+r)*(r-l+1)/2%mod;
    int s2=(S(r)-S(l-1)+mod)%mod;
    add(t[x],1ll*A*s2%mod);
    add(t[x],1ll*B*s1%mod);
    add(t[x],1ll*C*s0%mod);
    add(a[x],A),add(b[x],B),add(c[x],C);
}
inline void pushdown(register int x,register int l,register int r)
{
    if(!(a[x]||b[x]||c[x]))
        return;
    int mid=l+r>>1;
    put(x<<1,l,mid,a[x],b[x],c[x]);
    put(x<<1|1,mid+1,r,a[x],b[x],c[x]);
    a[x]=b[x]=c[x]=0;
}
inline void modify(register int x,register int l,register int r,register int insl,register int insr,register int a,register int b,register int c)
{
    if(insl<=l&&r<=insr)
    {
        put(x,l,r,a,b,c);
        return;
    }
    int mid=l+r>>1;
    pushdown(x,l,r);
    if(insl<=mid)
        modify(x<<1,l,mid,insl,insr,a,b,c);
    if(insr>mid)
        modify(x<<1|1,mid+1,r,insl,insr,a,b,c);
    t[x]=(t[x<<1]+t[x<<1|1])%mod;
}
inline int query(register int x,register int l,register int r,register int insl,register int insr)
{
    if(insl<=l&&r<=insr)
        return t[x];
    pushdown(x,l,r);
    int mid=l+r>>1,res=0;
    if(insl<=mid)
        res+=query(x<<1,l,mid,insl,insr);
    if(insr>mid)
        res+=query(x<<1|1,mid+1,r,insl,insr);
    return res%mod;
}
int main()
{
    n=read(),m=read();
    for(register int i=1,x,s=0,ss=0;i<=n;++i)
    {
        x=read();
        add(s,x);
        add(ss,s);
        modify(1,0,n,i,i,0,0,ss);
    }
    for(register int i=1;i<=m;++i)
    {
        int op=read();
        if(op==1)
        {
            int l=read(),r=read(),v=read();
            if(l>r)
                l^=r^=l^=r;
            v=1ll*v*inv2%mod;
            int a=v,b=(1ll*(3-2*l)*v%mod+mod)%mod;
            int c=(1ll*v*(1ll*l*l%mod-3ll*l+2)%mod+mod)%mod;
            modify(1,0,n,l,r,a,b,c);
            a=0,b=2ll*(r-l+1)*v%mod;
            c=(1ll*(r-l+1)*(r-l+2)%mod*v%mod-1ll*r*b%mod+mod)%mod;
            if(r!=n)
                modify(1,0,n,r+1,n,a,b,c);
        }
        else
        {
            int l=read(),r=read();
            if(l>r)
                l^=r^=l^=r;
            int ans=1ll*query(1,0,n,n,n)*(r-l+1)%mod;
            add(ans,mod-query(1,0,n,l-1,r-1));
            add(ans,mod-query(1,0,n,n-r,n-l));
            write(ans),puts("");
        }
    }
	return 0;
}

R2T3治疗之雨

题意好像不太清楚,或许是我语文太差

实际就是每轮操作随机一个不满血的加一滴血,随机\(k\)个减一滴血,问期望多少回合后血量会为0

我们设\(p_x\)表示一次操作扣\(x\)滴血的概率

\[p_x=\tbinom{k}{x} (\frac{1}{m+1})^x (\frac{m}{m+1})^{k-x} \]

我们设\(E_x\)表示还有\(i\)滴血时期望多少回合后血量会为0

对于\(i \in [1,n-1]\)

\[E_{i}=\left(\sum_{j=1}^{j}\left(\frac{m}{m+1} p_{i-j}+\frac{1}{m+1} p_{i-j+1}\right) E_{j}\right)+\left(\frac{1}{m+1} p_{0}\right) E_{i+1}+1 \]

对于\(i=n\)

\[E_{n}=\left(\sum_{j=1}^{n} p_{n-j} E_{j}\right)+1 \]

进行高斯消元即可,于是我们就得到了能拿70pts的好做法

发现这个矩阵很有特点,几乎是一个下三角矩阵,所以我们珂以用\(n^2\)的时间求解,总复杂度\(O(Tn^2)\)

#include <bits/stdc++.h>
#define mod 1000000007
#define N 1505
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
inline int power(register int a,register int b)
{
    int res=1;
    while(b)
    {
        if(b&1)
            res=1ll*res*a%mod;
        a=1ll*a*a%mod;
        b>>=1;
    }
    return res;
}
int T,n,p,m,k,inv[N],P[N],F[N][N],f[N];
inline int work()
{
    memset(P,0,sizeof(P));
    n=read(),p=read(),m=read(),k=read();
    if(!k||(m==0&&k==1))
        return -1;
    if(m==0)
    {
        int res=0;
        for(;p>0;p-=k,++res)
            if(p<n)
                ++p;
        return res;
    }
    int inva=power(m+1,mod-2);
    inv[1]=1;
    for(register int i=2;i<=n+1;++i)
        inv[i]=mod-1ll*mod/i*inv[mod%i]%mod;
    for(register int i=0,C=1;i<=min(n,k);C=1ll*C*inv[i+1]%mod*(k-i)%mod,++i)
        P[i]=1ll*C*power(inva,i)%mod*power(1ll*m*inva%mod,k-i)%mod;
    for(register int i=1;i<n;++i)
    {
        for(register int j=1;j<=i;++j)
            F[i][j]=(1ll*m*inva%mod*P[i-j]%mod+1ll*inva*P[i-j+1]%mod)%mod;
        F[i][i+1]=1ll*inva*P[0]%mod;
        (F[i][i]+=mod-1)%=mod;
        F[i][n+1]=mod-1;
    }
    for(register int i=1;i<=n;++i)
        F[n][i]=P[n-i];
    (F[n][n]+=mod-1)%=mod;
    F[n][n+1]=mod-1;
    for(register int i=n;i>=2;--i)
    {
        if(!F[i][i])
            return -1;
        int t=1ll*F[i-1][i]*power(F[i][i],mod-2)%mod;
        for(register int j=i;j>=1;--j)
            F[i-1][j]=(F[i-1][j]-1ll*F[i][j]*t%mod+mod)%mod;
        F[i-1][n+1]=(F[i-1][n+1]-1ll*F[i][n+1]*t%mod+mod)%mod;
    }
    for(register int i=1;i<=n;++i)
    {
        int res=F[i][n+1];
        for(register int j=1;j<i;++j)
            res=(res-1ll*f[j]*F[i][j]%mod+mod)%mod;
        f[i]=1ll*res*power(F[i][i],mod-2)%mod;
    }
    return f[p];
}
int main()
{
    T=read();
    while(T--)
        write(work()),puts("");
	return 0;
}
posted @ 2019-08-09 21:37  JSOI爆零珂学家yzhang  阅读(439)  评论(3编辑  收藏  举报