• TJOI2018简要题解


    Day1T1数学计算

    按照时间轴建一棵线段树即可,复杂度为(O(m log m))

    #include <bits/stdc++.h>
    #define N 100005
    #define ll long long
    #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 ll read()
    {
        register ll 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 n;
    ll mod;
    struct SegmentTree{
    	ll mul[N<<3];
    	inline void init(register int x,register int l,register int r)
    	{
    		mul[x]=1;
    		if(l==r)
    			return;
    		int mid=l+r>>1;
    		init(x<<1,l,mid);
    		init(x<<1|1,mid+1,r);
    	}
    	inline void pushup(register int x)
    	{
    		mul[x]=mul[x<<1]*mul[x<<1|1]%mod;
    	}
    	inline void update(register int x,register int l,register int r,register int pos,register int v)
    	{
    		if(l==r)
    		{
    			mul[x]=v;
    			return;
    		}
    		int mid=l+r>>1;
    		if(pos<=mid)
    			update(x<<1,l,mid,pos,v);
    		else 
    			update(x<<1|1,mid+1,r,pos,v);
    		pushup(x);
    	}
    }tr;
    int main()
    {
    	int T=read();
    	while(T--)
    	{
    		n=read(),mod=read();
    		tr.init(1,1,n);
    		for(register int i=1;i<=n;++i)
    		{
    			int opt=read();
    			ll x=read();
    			if(opt==1)
    				tr.update(1,1,n,i,x);
    			else
    				tr.update(1,1,n,x,1);
    			write(tr.mul[1]),puts("");
    		}
    	}
    	return 0;
     } 
    

    Day1T2智力竞赛

    考虑二分答案,二分的是最大能覆盖到的权值

    这样我们就将问题转化成一个DAG能否被(n+1)条可重链覆盖

    这就是一个经典问题了,先跑一下弗洛伊德传递闭包,然后二分图最大匹配即可,复杂度为(O(m^3+m^3 log m ))

    #include <bits/stdc++.h>
    #define N 505
    #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 n,m,o[N],v[N],G[N][N],GN[N][N],link[N],vis[N];
    inline bool Hungary(register int x)
    {
        for(register int v=1;v<=m;++v)
        {
            if(!GN[x][v]||vis[v])
                continue;
            vis[v]=1;
            if(!link[v]||Hungary(link[v]))
                return link[v]=x;
        }
        return 0;
    }
    inline bool check(register int mid)
    {
        int res=0;
        for(register int i=1;i<=m;++i)
            if(v[i]<=mid)
                ++res;
        for(register int i=1;i<=m;++i)
            for(register int j=1;j<=m;++j)
            {
                if(v[i]<=mid&&v[j]<=mid)
                    GN[i][j]=G[i][j];
                else
                    GN[i][j]=0;
            }
        memset(link,0,sizeof(link));
        for(register int i=1;i<=m;++i)
        {
            if(v[i]>mid)
                continue;
            memset(vis,0,sizeof(vis));
            if(Hungary(i))
                --res;
        }
        return res<=n;
    }
    int main()
    {
        n=read()+1,m=read();
        for(register int i=1;i<=m;++i)
        {
            o[i]=v[i]=read();
            int cnt=read();
            while(cnt--)
                G[i][read()]=1;
        }
        for(register int k=1;k<=m;++k)
            for(register int i=1;i<=m;++i)
                for(register int j=1;j<=m;++j)
                    G[i][j]|=G[i][k]&G[k][j];
        sort(o+1,o+m+1);
        if(check(o[m]+1))
        {
            puts("AK");
            return 0;
        }
        int l=1,r=m-1;
        while(l<r)
        {
            int mid=l+r+1>>1;
            if(check(o[mid]))
                l=mid;
            else
                r=mid-1;
        }
        write(o[l+1]);
    	return 0;
    }
    
    

    Day1T3游园会

    这题和麻将是一个套路,考的是一个叫做dp套dp的神奇科技

    发现奖章串的长度小于等于15,所以可以考虑把15位的dp数组作为转移的状态

    回想一下lcs的求法,dp相邻的两个值最多差1,可以考虑状压

    (f[i][j][0/1/2])表示匹配到兑奖串的第(i)位,(dp)状态为j,最后与“NOI”的匹配位数为0/1/2,转移显然

    直接做空间会炸,第一位滚一下即可,复杂度为(O(nk2^k))

    #include <bits/stdc++.h>
    #define mod 1000000007
    #define N 1005
    using namespace std;
    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;
    }
    int n,l,tot;
    char s[20];
    int dp[2][N],f[2][1<<15][3],ans[N];
    inline void decode(register int sta)
    {
        for(register int i=1;i<=l;++i)
            dp[0][i]=(sta>>(i-1))&1;
        for(register int i=1;i<=l;++i)
            dp[0][i]+=dp[0][i-1];
    }
    inline int encode()
    {
        int res=0;
        for(register int i=1;i<=l;++i)
            if(dp[1][i]-dp[1][i-1])
                res|=1<<(i-1);
        return res;
    }
    inline void trans(register int i,register int j,register int k,register char c,register int v)
    {
        decode(j);
        for(register int p=1;p<=l;++p)
        {
            dp[1][p]=max(dp[1][p-1],dp[0][p]);
            dp[1][p]=max(dp[1][p],dp[0][p-1]+(c==s[p]));
        }
        add(f[i][encode()][k],v);
    }
    int main()
    {
        n=read(),l=read(),tot=1<<l;
        scanf("%s",s+1);
        f[0][0][0]=1;
        for(register int i=0;i<n;++i)
        {
            int now=i&1,nxt=now^1;
            memset(f[nxt],0,sizeof(f[nxt]));
            for(register int j=0;j<tot;++j)
            {
                if(f[now][j][0])
                {
                    trans(nxt,j,1,'N',f[now][j][0]);
                    trans(nxt,j,0,'O',f[now][j][0]);
                    trans(nxt,j,0,'I',f[now][j][0]);
                }
                if(f[now][j][1])
                {
                    trans(nxt,j,1,'N',f[now][j][1]);
                    trans(nxt,j,2,'O',f[now][j][1]);
                    trans(nxt,j,0,'I',f[now][j][1]);
                }
                if(f[now][j][2])
                {
                    trans(nxt,j,1,'N',f[now][j][2]);
                    trans(nxt,j,0,'O',f[now][j][2]);
                }
            }
        }
        for(register int i=0;i<tot;++i)
            for(register int j=0;j<=2;++j)
                add(ans[__builtin_popcount(i)],f[n&1][i][j]);
        for(register int i=0;i<=l;++i)
            write(ans[i]),puts("");
    	return 0;
    }
    

    Day2T1碱基序列

    kmp来优化dp,设(dp_{i,j})表示处理完了(i)个碱基序列,匹配到第(j)位的方案数,转移显然

    空间不够,滚动一下即可,复杂度为(O(T sum a_i |s|))

    #include <bits/stdc++.h>
    #define mod 1000000007
    #define N 100005
    using namespace std;
    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 m,n,f[2][N],now,nxt[N],ans;
    char s[N],t[N];
    int main()
    {
        m=read();
        scanf("%s",s+1);
        n=strlen(s+1);
        for(register int i=0;i<=n;++i)
            f[now][i]=1;
        now^=1;
        while(m--)
        {
            memset(f[now],0,sizeof(f[now]));
            int cnt=read();
            while(cnt--)
            {
                scanf("%s",t+1);
                int len=strlen(t+1);
                nxt[1]=0;
                for(register int i=1,k=0;i<len;++i)
                {
                    while(k&&t[i+1]!=t[k+1])
                        k=nxt[k];
                    nxt[i+1]=(t[i+1]==t[k+1]?++k:0);
                }
                for(register int i=1,k=0;i<=n;++i)
                {
                    while(k&&s[i]!=t[k+1])
                        k=nxt[k];
                    k+=(s[i]==t[k+1]);
                    if(k==len)
                        f[now][i]=(f[now][i]+f[now^1][i-k])%mod;
                }
            }
            now^=1;
        }
        now^=1;
        for(register int i=0;i<=n;++i)
            ans=(ans+f[now][i])%mod;
        write(ans);
    	return 0;
    }
    

    Day2T2异或

    珂以直接大力树剖,按dfs序建可持久化01trie,子树查询就是区间查询,链查询靠树剖变成一堆区间查询

    这个复杂度为(O(32 m log n)),实际复杂度珂以更优,对于子树查询按dfs序建01trie,区间查询,对于链查询按dep建01trie,树上差分后区间查询,复杂度优化为(O(32 m))

    由于我比较懒,我只写了(O(32 m log n))的做法(划掉

    #include <bits/stdc++.h>
    #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 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 Max(register int a,register int b)
    {
    	return a>b?a:b;
    }
    struct edge{
    	int to,next;
    }e[N<<1];
    int head[N],cnt=0;
    inline void add(register int u,register int v)
    {
    	e[++cnt]=(edge){v,head[u]};
    	head[u]=cnt;
    }
    int n,q,v[N],root[N]; 
    int son[N],fa[N],size[N],dep[N],top[N],dfn[N],tim;
    struct node{
    	int ch[2],sum;
    }tr[N*80];
    int tot=0;
    inline void insert(register int &rt,register int pre,register int bit,register int val)
    {
    	rt=++tot;
    	tr[rt]=tr[pre];
    	++tr[rt].sum;
    	if(bit==-1)
    		return;
    	int f=(val>>bit)&1;
    	insert(tr[rt].ch[f],tr[pre].ch[f],bit-1,val);
    }
    inline int query(register int a,register int b,register int bit,register int val)
    {
    	if(bit==-1)
    		return 0;
    	int f=((val>>bit)&1)^1;
    	if(tr[tr[b].ch[f]].sum>tr[tr[a].ch[f]].sum)
    		return (1<<bit)+query(tr[a].ch[f],tr[b].ch[f],bit-1,val);
    	else
    		return query(tr[a].ch[f^1],tr[b].ch[f^1],bit-1,val);
    }
    inline void dfs1(register int x)
    {
    	size[x]=1;
    	for(register int i=head[x];i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if(v==fa[x])
    			continue;
    		dep[v]=dep[x]+1;
    		fa[v]=x;
    		dfs1(v);
    		size[x]+=size[v];
    		if(size[son[x]]<size[v])
    			son[x]=v;
    	}
    }
    inline void dfs2(register int x,register int t)
    {
    	top[x]=t;
    	dfn[x]=++tim;
    	insert(root[tim],root[tim-1],30,v[x]);
    	if(son[x])
    		dfs2(son[x],t);
    	for(register int i=head[x];i;i=e[i].next)
    	{
    		int v=e[i].to;
    		if(v==fa[x]||v==son[x])
    			continue;
    		dfs2(v,v);
    	}
    }
    inline int cal(register int x,register int y,register int z)
    {
    	int res=0;
    	int fx=top[x],fy=top[y];
    	while(fx!=fy)
    	{
    		if(dep[fx]<dep[fy])
    		{
    			x^=y^=x^=y;
    			fx^=fy^=fx^=fy;
    		}
    		res=Max(res,query(root[dfn[fx]-1],root[dfn[x]],30,z));
    		x=fa[fx];
    		fx=top[x];
    	}
    	if(dep[x]>dep[y])
    		x^=y^=x^=y;
    	res=Max(res,query(root[dfn[x]-1],root[dfn[y]],30,z));
    	return res;
    }
    int main()
    {
    	n=read(),q=read();
    	for(register int i=1;i<=n;++i)
    		v[i]=read();
    	for(register int i=1;i<n;++i)
    	{
    		int u=read(),v=read();
    		add(u,v),add(v,u);
    	}
    	dfs1(1);
    	dfs2(1,0);
    	while(q--)
    	{
    		int opt=read();
    		if(opt==1)
    		{
    			int x=read(),y=read();
    			write(query(root[dfn[x]-1],root[dfn[x]+size[x]-1],30,y)),puts("");
    		}
    		else
    		{
    			int x=read(),y=read(),z=read();
    			write(cal(x,y,z)),puts("");
    		}
    	}
    	return 0;
    }
    

    Day2T3教科书般的亵渎

    [S(x)=sum_{i=1}^{x} i^{m+1} ]

    [Ans=sum_{i=0}^{m}left(Sleft(n-a_{i} ight)-sum_{j=i+1}^{m}left(a_{j}-a_{i} ight)^{m+1} ight) ]

    珂以证明(S(x))是个(m+3)次多项式(珂以用一次二次三次函数类比,但严谨的证明还是需要通过数学归纳法的),可以用拉格朗日插值快速处理,复杂度为(O(T m^2 log p)),预处理逆元的话能做到(O(T m^2))

    #include <bits/stdc++.h>
    #define ll long long
    #define mod 1000000007
    #define N 55
    #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 ll read()
    {
        register ll 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 ll a,register int b)
    {
        a%=mod;
        int res=1;
        while(b)
        {
            if(b&1)
                res=1ll*res*a%mod;
            a=1ll*a*a%mod;
            b>>=1;
        }
        return res;
    }
    ll T,n,m,a[N],f[N];
    inline int calc(register ll d,register int n)
    {
        if(d<=n)
            return f[d];
        int o=(n&1)?-1:1,tmp=1,ans=0;
        for(register int i=1;i<=n;++i)
            tmp=1ll*(d-i)%mod*tmp%mod;
        for(register int i=1;i<=n;++i)
            tmp=1ll*tmp*power(i,mod-2)%mod;
        for(register int i=0;i<=n;++i,o=-o)
        {
            ans=(ans+1ll*o*f[i]%mod*tmp%mod)%mod;
            tmp=1ll*(d-i)%mod*tmp%mod*power(d-i-1,mod-2)%mod;
            tmp=1ll*tmp*(n-i)%mod*power(i+1,mod-2)%mod;
        }
        return (ans+mod)%mod;
    }
    int main()
    {
        T=read();
        while(T--)
        {
            n=read(),m=read();
            for(register int i=1;i<=m;++i)
                a[i]=read();
            for(register int i=1;i<=m+3;++i)
                f[i]=(f[i-1]+power(i,m+1))%mod;
            sort(a+1,a+m+1);
            int ans=0;
            for(register int i=0;i<=m;++i)
            {
                ans=(ans+calc(n-a[i],m+3))%mod;
                for(register int j=i+1;j<=m;++j)
                    ans=(0ll+ans+mod-power(a[j]-a[i],m+1))%mod;
            }
            write(ans),puts("");
        }
    	return 0;
    }
    
    
  • 相关阅读:
    【学习笔记】Python 3.6模拟输入并爬取百度前10页密切相关链接
    socket编程
    2.4.2电子书fb.c文件
    3.1 电子书框架
    文件浏览器及数码相框 -2.3.2-freetype_arm-2
    文件浏览器及数码相框 -2.3.2-freetype_arm-1
    文件浏览器及数码相框 -2.3.1freetype_pc
    文件浏览器及数码相框 -2.2-字符点阵及汉字库
    文件浏览器及数码相框 -2.1-字符编码
    文件浏览器及数码相框-1
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/11337676.html
Copyright © 2020-2023  润新知