TJOI2018 简要题解

数学计算

用线段树记录之前乘过的每一个数,作除法时把原本的乘数改成111即可。

代码:

#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
#define N 100005
using namespace std;
int t,n;
long long mod;
inline long long read(){
    long long ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();
    return ans;
}
struct Node{int l,r;long long mul;}T[N<<2];
inline void pushup(int p){T[p].mul=T[lc].mul*T[rc].mul%mod;}
inline void build(int p,int l,int r){
    T[p].l=l,T[p].r=r,T[p].mul=1;
    if(l==r)return;
    build(lc,l,mid);
    build(rc,mid+1,r);
}
inline void update(int p,int k,int v){
    if(T[p].l==T[p].r){
        T[p].mul=v;
        return;
    }
    if(k<=mid)update(lc,k,v);
    else update(rc,k,v);
    pushup(p);
}
int main(){
    t=read();
    while(t--){
        n=read(),mod=read();
        build(1,1,n);
        for(int i=1;i<=n;++i){
            int op=read();
            if(op==1){long long v=read();update(1,i,v);}
            else{int pos=read();update(1,pos,1);}
            printf("%lld\n",T[1].mul);
        }
    }
    return 0;
}

智力竞赛

这是一道语文阅读题

二分答案之后上最小链覆盖即可。

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
const int N=505;
bool trans[N][N],tmp[N][N],e[N][N],vis[N];
int mp[N],lim,n,m,matching[N];
struct Node{
    int id,w;
    friend inline bool operator<(const Node&a,const Node&b){return a.w<b.w;}
}a[N];
inline bool find(int x,int Lim){
    for(ri i=1;i<=Lim;++i){
        if(!trans[x][i]||vis[i])continue;
        vis[i]=1;
        if(!matching[i]||find(matching[i],Lim))return matching[i]=x,1;
    }
    return 0;
}
inline int match(int Lim){
    int ret=0;
    memset(matching,0,sizeof(matching));
    for(ri i=1;i<=Lim;++i){
        memset(vis,0,sizeof(vis));
        if(find(i,Lim))++ret;
    }
    return ret;
}
inline bool check(int Lim){
    memset(trans,0,sizeof(trans));
    for(ri i=1;i<=Lim;++i)for(ri j=1;j<=Lim;++j)trans[i][j]=e[i][j];
    for(ri k=1;k<=Lim;++k)for(ri i=1;i<=Lim;++i)if(trans[i][k])
    for(ri j=1;j<=Lim;++j)if(trans[k][j])trans[i][j]=1;
    return Lim-match(Lim)<=lim;
}
int main(){
    lim=read()+1,n=read();
    for(ri i=1;i<=n;++i){
        a[i]=(Node){i,read()};
        for(ri tt=read();tt;--tt)tmp[i][read()]=1;
    }
    sort(a+1,a+n+1);
    for(ri i=1;i<=n;++i)mp[a[i].id]=i;
    for(ri i=1;i<=n;++i)for(ri j=1;j<=n;++j)e[mp[i]][mp[j]]=tmp[i][j];
    int l=1,r=n,ans=1;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid))l=mid+1,ans=mid;
        else r=mid-1;
    }
    if(r^n)cout<<a[ans+1].w;
    else puts("AK");
    return 0;
}

party

好题。

考虑lcslcslcs的性质。

fi,j=max{fi−1,j,fi,j−1,fi−1,j−1+[si==tj]}f_{i,j}=max\{f_{i-1,j},f_{i,j-1},f_{i-1,j-1}+[s_i==t_j]\}fi,j​=max{fi−1,j​,fi,j−1​,fi−1,j−1​+[si​==tj​]}

于是fi,j−fi−1,j=0/1f_{i,j}-f_{i-1,j}=0/1fi,j​−fi−1,j​=0/1,我们把这个东西拿来状压,然后转移即可。

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1005,M=1<<16,mod=1e9+7;
int tt,n,f[2][M][3],tran1[20],tran2[20],tmp=0,ans[20],bit[M];
char s[20];
inline void trans(int sta,int a[]){
    a[0]=0;
    for(ri i=1;i<=n;++i)a[i]=a[i-1]+((sta>>(i-1))&1);
}
inline int inv_trans(int a[]){
    int ret=0;
    for(ri i=1;i<=n;++i)ret|=(a[i]-a[i-1])<<(i-1);
    return ret;
}
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline void update(int&a,const int&b){a=add(a,b);}
inline int max(const int&a,const int&b,const int&c){return a>b?(a>c?a:c):(b>c?b:c);}
inline void update(int pos,int sta,int len,char x,int upd){
    trans(sta,tran1);
    for(ri i=1;i<=n;++i)tran2[i]=max(tran2[i-1],tran1[i],tran1[i-1]+(x==s[i]));
    int nsta=inv_trans(tran2);
    update(f[pos][nsta][len],upd);
}
int main(){
    scanf("%d%d%s",&tt,&n,s+1);
    for(ri i=1,up=1<<n;i<up;++i)bit[i]=bit[i>>1]+(i&1);
    f[0][0][0]=1;
    for(ri up=1<<n;tt;--tt){
        memset(f[tmp^1],0,sizeof(f[tmp^1]));
        for(ri i=0;i<up;++i){
            if(f[tmp][i][0]){
                update(tmp^1,i,1,'N',f[tmp][i][0]);
                update(tmp^1,i,0,'O',f[tmp][i][0]);
                update(tmp^1,i,0,'I',f[tmp][i][0]);
            }
            if(f[tmp][i][1]){
                update(tmp^1,i,1,'N',f[tmp][i][1]);
                update(tmp^1,i,2,'O',f[tmp][i][1]);
                update(tmp^1,i,0,'I',f[tmp][i][1]);
            }
            if(f[tmp][i][2]){
                update(tmp^1,i,1,'N',f[tmp][i][2]);
                update(tmp^1,i,0,'O',f[tmp][i][2]);
            }
        }
        tmp^=1;
    }
    for(ri i=0,up=1<<n;i<up;++i)for(ri j=0;j<3;++j)update(ans[bit[i]],f[tmp][i][j]);
    for(ri i=0;i<=n;++i)cout<<ans[i]<<'\n';
    return 0;
}

str

对于每个碱基序列用kmpkmpkmp处理出failfailfail数组来进行dpdpdp转移即可。

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=10005,mod=1e9+7;
typedef long long ll;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline void update(int&a,const int&b){a=add(a,b);}
int k,ans=0,Tt,n,f[2][N],tmp=0,m,fail[N];
char s[N],t[N];
int main(){
    scanf("%d%s",&Tt,s+1),n=strlen(s+1);
    for(ri i=0;i<=n;++i)f[0][i]=1;
    for(ri tt;Tt;--Tt){
        tmp^=1,memset(f[tmp],0,sizeof(f[tmp])),scanf("%d",&tt);
        while(tt--){
            scanf("%s",t+1),m=strlen(t+1);
            for(ri i=1,j=0;i<m;++i){
                while(j&&t[i+1]!=t[j+1])j=fail[j];
                fail[i+1]=t[i+1]==t[j+1]?++j:0;
            }
            for(ri i=1,j=0;i<=n;++i){
                while(j&&s[i]!=t[j+1])j=fail[j];
                if(s[i]==t[j+1])++j;
                if(j==m)update(f[tmp][i],f[tmp^1][i-m]);
            }
        }
    }
    for(ri i=0;i<=n;++i)update(ans,f[tmp][i]);
    cout<<ans;
    return 0;
}

xor

额这个题不是把可持久化01trie01trie01trie放到树上来差个分就完了吗?

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int N=1e5+5;
struct Trie{
    int son[N*100][2],siz[N*100],tot;
    Trie(){tot=0,memset(son,0,sizeof(son)),memset(siz,0,sizeof(siz));}
    inline void insert(int &o,int las,int v){
        int p=++tot;
        o=p;
        for(ri i=31,tmp;~i;--i){
            tmp=(v>>i)&1;
            siz[p]=siz[las]+1,son[p][tmp^1]=son[las][tmp^1],son[p][tmp]=++tot;
            p=son[p][tmp],las=son[las][tmp];
        }
        siz[p]=siz[las]+1;
    }
    inline int query1(int pl,int pr,int v){
        int ret=0;
        for(ri i=31,tmp;~i;--i){
            tmp=(v>>i)&1;
            if(siz[son[pr][tmp^1]]!=siz[son[pl][tmp^1]])ret|=1<<i,pl=son[pl][tmp^1],pr=son[pr][tmp^1];
            else pl=son[pl][tmp],pr=son[pr][tmp];
        }
        return ret;
    }
    inline int query2(int pa,int pb,int pc,int pd,int v){
        int ret=0;
        for(ri i=31,tmp;~i;--i){
            tmp=(v>>i)&1;
            if(siz[son[pa][tmp^1]]+siz[son[pb][tmp^1]]-siz[son[pc][tmp^1]]-siz[son[pd][tmp^1]]){
                ret|=1<<i;
                pa=son[pa][tmp^1],pb=son[pb][tmp^1],pc=son[pc][tmp^1],pd=son[pd][tmp^1];
            }
            else pa=son[pa][tmp],pb=son[pb][tmp],pc=son[pc][tmp],pd=son[pd][tmp];
        }
        return ret;
    }
}T1,T2;
int n,q,rt1[N],rt2[N],siz[N],top[N],pred[N],tot=0,hson[N],dep[N],fa[N],num[N],a[N];
vector<int>e[N];
void dfs1(int p){
    siz[p]=1;
    for(ri i=0,v;i<e[p].size();++i){
        if((v=e[p][i])==fa[p])continue;
        fa[v]=p,dep[v]=dep[p]+1,dfs1(v),siz[p]+=siz[v];
        if(siz[v]>siz[hson[p]])hson[p]=v;
    }
}
void dfs2(int p,int tp){
    top[p]=tp,pred[num[p]=++tot]=p;
    T1.insert(rt1[p],rt1[fa[p]],a[p]);
    if(!hson[p])return;
    dfs2(hson[p],tp);
    for(ri i=0,v;i<e[p].size();++i)if((v=e[p][i])!=fa[p]&&v!=hson[p])dfs2(v,v);
}
inline int lca(int x,int y){
    while(top[x]^top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]<dep[y]?x:y;
}
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
int main(){
    n=read(),q=read();
    for(ri i=1;i<=n;++i)a[i]=read();
    for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
    dfs1(1),dfs2(1,1);
    for(ri i=1;i<=n;++i)T2.insert(rt2[i],rt2[i-1],a[pred[i]]);
    for(ri op,x,y,t;q;--q){
        op=read(),x=read(),y=read();
        if(op==1)cout<<T2.query1(rt2[num[x]-1],rt2[num[x]+siz[x]-1],y)<<'\n';
        else t=lca(x,y),cout<<T1.query2(rt1[x],rt1[y],rt1[t],rt1[fa[t]],read())<<'\n';
    }
    return 0;
}


教科书般的*

发现要维护这个东西:f(x,k)=∑i=1xikf(x,k)=\sum_{i=1}^xi^kf(x,k)=∑i=1x​ik

然后这个肯定是个kkk次多项式,于是拉格朗日插值把多项式求出来就完了。代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int mod=1e9+7,N=105;
typedef long long ll;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return (ll)a*b%mod;}
inline void update(int&a,const int&b){a=add(a,b);}
inline int ksm(int a,int p){int ret=1;for(;p;p>>=1,a=mul(a,a))if(p&1)ret=mul(ret,a);return ret;}
ll n,a[N];
int m,k,f[N],inv[N];
inline int lagrange(int x,int n){
    if(x<=k+2)return f[x];
    int ret=0;
    for(ri i=1,mult;i<=n;++i){
        mult=f[i];
        for(ri j=1;j<=n;++j){
            if(i>j)mult=mul(mult,mul(inv[i-j],dec(x,j)));
            if(i<j)mult=mul(mult,mul(mod-inv[j-i],dec(x,j)));
        }
        ret=add(ret,mult);
    }
    return ret;
}
int main(){
    inv[1]=1;
    for(ri i=2;i<=55;++i)inv[i]=mul(inv[mod-mod/i*i],mod-mod/i);
    int tt;
    scanf("%d",&tt);
    while(tt--){
        scanf("%lld%d",&n,&m),k=m+1;
        for(ri i=1;i<=m;++i)scanf("%lld",&a[i]);
        sort(a+1,a+m+1);
        a[m+1]=n+1;
        f[1]=1;
        for(ri i=2;i<=k+2;++i)f[i]=add(f[i-1],ksm(i,k));
        int ans=0;
        for(ri i=0;i<=m;++i)for(ri j=i+1;j<=m+1;++j){
            ans=add(ans,lagrange((a[j]-a[i]-1)%mod,k+2));
            ans=dec(ans,lagrange((a[j-1]-a[i])%mod,k+2));
        }
        cout<<ans<<'\n';
    }
    return 0;
}
上一篇:确定要包含的Delphi运行时程序包(Determining Delphi Runtime Packages to Include)


下一篇:tomcat源码阅读之BackupManager