zoukankan      html  css  js  c++  java
  • 2021ccpc预选重赛

    F

    (dp)出前(i)个位置匹配了多少个(nunhehheh),再统计每个位置后面(a)的个数即可计算答案

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 100100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    namespace CALC
    {
    	inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:(a+b<0?a+b+MOD:a+b);}
    	inline int mns(int a,int b){return a-b<0?a-b+MOD:(a-b>=MOD?a-b-MOD:a-b);}
    	inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    	inline void inc(int &a,int b){a=pls(a,b);}
    	inline void dec(int &a,int b){a=mns(a,b);}
    	inline void tms(int &a,int b){a=mul(a,b);}
    	inline int qp(int x,int t,int res=1)
    		{for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    	inline int Inv(int x){return qp(x,MOD-2);}
    }
    using namespace CALC;
    int n,pw[MAXN],f[MAXN][10],sum[10],numa[MAXN],ans;
    char s[MAXN];
    int main()
    {
    	pw[0]=1;rep(i,1,1e5) pw[i]=mul(pw[i-1],2);
    	rep(T,1,read())
    	{
    		scanf("%s",s+1);n=strlen(s+1);
    		numa[n+1]=0;ans=0;Fill(sum,0);
    		dwn(i,n,1) numa[i]=numa[i+1]+(s[i]=='a');
    		rep(i,1,n)
    		{
    			Fill(f[i],0);
    			if(s[i]=='n') f[i][0]=1,f[i][2]=sum[1];
    			else if(s[i]=='u') f[i][1]=sum[0];
    			else if(s[i]=='h')
    				f[i][3]=sum[2],f[i][5]=sum[4],f[i][6]=sum[5],f[i][8]=sum[7];
    			else if(s[i]=='e') f[i][4]=sum[3],f[i][7]=sum[6];
    			rep(j,0,8) inc(sum[j],f[i][j]);
    			inc(ans,mul(f[i][8],mns(pw[numa[i+1]],1)));
    		}
    		printf("%d
    ",ans);
    	}
    }
    

    H

    对于一个(m)的排列,分两类情况讨论

    1.当这个排列完全属于一个(n)的排列时,容易得到此时贡献为(m!(n-m+1)!)

    2.否则该排列被分成两个部分,分别存在于两个相邻的排列中

    先不考虑排列数加一造成的影响,则此时贡献为((m-1)m!(n-m)!)

    和上式加和可得(ncdot m!(n-m)!),即(m)的排列可以放在任意位置,超出去的部分放到(n)个位置的前面

    由于这种情况要求两个相邻的(n)排列的前面一部分一样

    将该(n)排列分为三部分(a b c),其中(a c)中的所有数均(le m)(b)中的数(>m)

    容易发现当且仅当(b c)部分为一个单调下降序列时,这个排列的下一个排列前面才不会是(a)部分,否则均满足条件

    考虑枚举(c)的长度,则前面(a)的部分随意排列,

    不合法情况总数为:(sumlimits_{i=1}^{m-1}inom{m}{i}(m-i)!=sumlimits_{i=1}^{m-1}frac{m!}{i!}=m!sumlimits_{i=1}^{m-1}frac{1}{i!})

    最终答案为(m!(n(n-m)!-sumlimits_{i=1}^{m-1}frac{1}{i!}))

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 1001001
    #define MOD 1000000007
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    namespace CALC
    {
    	inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:(a+b<0?a+b+MOD:a+b);}
    	inline int mns(int a,int b){return a-b<0?a-b+MOD:(a-b>=MOD?a-b-MOD:a-b);}
    	inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    	inline void inc(int &a,int b){a=pls(a,b);}
    	inline void dec(int &a,int b){a=mns(a,b);}
    	inline void tms(int &a,int b){a=mul(a,b);}
    	inline int qp(int x,int t,int res=1)
    		{for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    	inline int Inv(int x){return qp(x,MOD-2);}
    }
    using namespace CALC;
    int n,m,fac[MAXN],ifac[MAXN],sum[MAXN];
    void init(int n=1e6)
    {
    	fac[0]=ifac[0]=1;rep(i,1,n) fac[i]=mul(fac[i-1],i);
    	ifac[n]=Inv(fac[n]);dwn(i,n-1,1) ifac[i]=mul(ifac[i+1],i+1);
    	rep(i,1,n) sum[i]=pls(sum[i-1],ifac[i]);
    }
    int main()
    {
    	init();rep(T,1,read())
    	{
    		n=read(),m=read();
    		printf("%d
    ",mul(fac[m],mns(mul(fac[n-m],n),sum[m-1])));
    	}
    }
    

    I

    容易想到直接将边拆成点,但直接做显然复杂度无法接受

    将所有边同一起点的边按照(a_e)升序排列之后,每条边可以优化的边即在一段连续的区间内

    image

    如图所示,将每个点(x)拆成(deg_x+1)个点,所有边权为(a_e)边起点仍为(x),边权为(a_e-b_e)的边按(a_e)排序后起点不同,相邻的边起点直接升序连接0边

    对于终点为(v)的边,二分出合法区间,然后将(a_e)(a_e-b_e)的边均连向(a)最小的点即可 正确性容易验证

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 200100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    namespace CALC
    {
    	inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:(a+b<0?a+b+MOD:a+b);}
    	inline int mns(int a,int b){return a-b<0?a-b+MOD:(a-b>=MOD?a-b-MOD:a-b);}
    	inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    	inline void inc(int &a,int b){a=pls(a,b);}
    	inline void dec(int &a,int b){a=mns(a,b);}
    	inline void tms(int &a,int b){a=mul(a,b);}
    	inline int qp(int x,int t,int res=1)
    		{for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    	inline int Inv(int x){return qp(x,MOD-2);}
    }
    using namespace CALC;
    const ll inf=1e18;
    int n,m;
    int nxt[MAXN<<2],fst[MAXN<<1],to[MAXN<<2],val[MAXN<<2],cnt;
    int vis[MAXN<<1],l[MAXN],r[MAXN];
    struct Edge{int u,v,a,b;}e[MAXN];
    bool operator < (Edge x,Edge y){return x.u<y.u||(x.u==y.u&&x.a<y.a);}
    void add(int u,int v,int w){nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v,val[cnt]=w;}
    struct node{int x;ll dis;};
    bool operator < (node a,node b) {return a.dis>b.dis;}
    ll dis[MAXN<<1];
    priority_queue <node> q;
    inline void dij()
    {
        int a;
        rep(i,1,n+m) dis[i]=inf,vis[i]=0;dis[1]=0;
        q.push((node){1,0});
        while(!q.empty())
        {
            a=q.top().x;q.pop();if(vis[a]) continue;
            vis[a]=1;
            for(int i=fst[a];i;i=nxt[i])
                if(dis[to[i]]>dis[a]+val[i])
    				{dis[to[i]]=dis[a]+val[i];if(!vis[to[i]]) q.push((node){to[i],dis[to[i]]});};
        }
    }
    int main()
    {
        int v,ed;e[0].a=0,e[0].b=0;
    	rep(T,1,read())
        {
        	n=read(),m=read();
    		rep(i,1,n) l[i]=r[i]=0;
    		rep(i,1,n+m) fst[i]=0;cnt=0;
    		rep(i,1,m) scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].a,&e[i].b);
    		sort(e+1,e+m+1);
    		rep(i,1,m)
    		{
    			if(!l[e[i].u]) l[e[i].u]=i;
    			else add(i+n-1,i+n,0);
    			r[e[i].u]=i;
    		}
    		rep(i,1,n) if(r[i]) add(r[i]+n,i,0);
    		rep(i,1,m)
    		{
    			v=e[i].v;
    			if(!l[v]) ed=v;
    			else 
    			{
    				ed=upper_bound(e+l[v],e+r[v]+1,(Edge){e[i].v,0,e[i].a,0})-e;
    				if(ed>r[v]) ed=v;else ed+=n;
    			}
    			add(e[i].u,ed,e[i].a);
    			add(i+n,ed,e[i].a-e[i].b);
    		}
    		dij();
    		rep(i,1,n) printf("%lld%c",dis[i]==inf?-1:dis[i],i==n?'
    ':' ');
    	}
    }
    

    K

    由于所有点权均不相同,因此对于当前的连通块

    显然所有点都可以选择走到当前联通块内点权最大的点,然后把这个点删掉,继续递归这个过程

    事实上由于删点难以做到,我们考虑按照权值从小到大加入每个点

    每次遇到相邻的已经被访问过的连通块,就从这个新点向该连通块的根连边,这样每个点的深度即为答案

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 100100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    namespace CALC
    {
    	inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:(a+b<0?a+b+MOD:a+b);}
    	inline int mns(int a,int b){return a-b<0?a-b+MOD:(a-b>=MOD?a-b-MOD:a-b);}
    	inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    	inline void inc(int &a,int b){a=pls(a,b);}
    	inline void dec(int &a,int b){a=mns(a,b);}
    	inline void tms(int &a,int b){a=mul(a,b);}
    	inline int qp(int x,int t,int res=1)
    		{for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    	inline int Inv(int x){return qp(x,MOD-2);}
    }
    using namespace CALC;
    int n,nxt[MAXN<<1],to[MAXN<<1],cnt,fst[MAXN],dep[MAXN],vis[MAXN],fa[MAXN];
    pii g[MAXN];
    vector<int> G[MAXN];
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void add(int u,int v){nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
    void dfs(int x,int pa)
    {
    	dep[x]=dep[pa]+1;
    	for(auto v:G[x]) dfs(v,x);
    }
    int main()
    {
    	int a,b,x;rep(T,1,read())
    	{
    		n=read();cnt=0;
    		rep(i,1,n) fa[i]=i,vis[i]=fst[i]=0,G[i].clear();
    		rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a);
    		rep(i,1,n) g[i].fi=read(),g[i].se=i;
    		sort(g+1,g+n+1);
    		rep(i,1,n)
    		{
    			x=g[i].se;vis[x]=1;
    			ren if(vis[to[i]])
    				G[x].pb(find(to[i])),fa[find(to[i])]=x;
    		}
    		dfs(g[n].se,0);
    		rep(i,1,n) printf("%d
    ",dep[i]);
    	}
    }
    

    比赛时候用了一种非常麻烦的做法

    大概是按点权倒序加点,对每个点维护一个(now_i)

    每次查询这个点到该点最近被访问过的祖先这条链上的(now)最大值(+1)即为答案

    再把这条链上除最近被访问过的祖先以外的点的(now)用该点答案更新

    查询祖先过程可以用二分+(ST)表预处理,修改与查询用树链剖分+线段树维护

    #include<bits/stdc++.h>
    #define inf 2139062143
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    #define MAXN 200100
    #define MOD 998244353
    #define Fill(a,x) memset(a,x,sizeof(a))
    #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
    #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
    #define ren for(int i=fst[x];i;i=nxt[i])
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    namespace CALC
    {
    	inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:(a+b<0?a+b+MOD:a+b);}
    	inline int mns(int a,int b){return a-b<0?a-b+MOD:(a-b>=MOD?a-b-MOD:a-b);}
    	inline int mul(int a,int b){return (1LL*a*b)%MOD;}
    	inline void inc(int &a,int b){a=pls(a,b);}
    	inline void dec(int &a,int b){a=mns(a,b);}
    	inline void tms(int &a,int b){a=mul(a,b);}
    	inline int qp(int x,int t,int res=1)
    		{for(;t;t>>=1,x=mul(x,x)) if(t&1) res=mul(res,x);return res;}
    	inline int Inv(int x){return qp(x,MOD-2);}
    }
    using namespace CALC;
    int n,nxt[MAXN<<1],to[MAXN<<1],cnt,fst[MAXN],w[MAXN],h[MAXN],st[MAXN];
    int fmx[MAXN][20],ff[MAXN][20];
    pii g[MAXN];
    int bl[MAXN],sz[MAXN],dep[MAXN],fa[MAXN],hvs[MAXN],in[MAXN],out[MAXN],dfn;
    int mx[MAXN<<2],tag[MAXN<<2],ans[MAXN];
    void add(int u,int v){nxt[++cnt]=fst[u],fst[u]=cnt,to[cnt]=v;}
    void dfs(int x,int pa)
    {
        sz[x]=1,fa[x]=pa,fmx[x][0]=w[pa],ff[x][0]=fa[x],hvs[x]=0;
        rep(j,1,19)
    		ff[x][j]=ff[ff[x][j-1]][j-1],fmx[x][j]=max(fmx[x][j-1],fmx[ff[x][j-1]][j-1]);
    	ren if(to[i]^pa)
        {
    		dep[to[i]]=dep[x]+1;dfs(to[i],x);
    		sz[x]+=sz[to[i]],hvs[x]=sz[to[i]]>sz[hvs[x]]?to[i]:hvs[x];
    	}
    }
    void Dfs(int x,int anc)
    {
        bl[x]=anc,in[x]=out[x]=++dfn;
    	if(!hvs[x]) return ;Dfs(hvs[x],anc);
        ren if(to[i]^fa[x]&&to[i]^hvs[x]) Dfs(to[i],to[i]);out[x]=dfn;
    }
    void build(int k,int l,int r)
    {
    	tag[k]=mx[k]=0;if(l==r) return ;
    	int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
    }
    inline void pshd(int k)
    {
    	mx[k<<1]=mx[k<<1|1]=tag[k<<1]=tag[k<<1|1]=tag[k],tag[k]=0;
    }
    void mdf(int k,int l,int r,int a,int b,int x)
    {
    	if(a<=l&&r<=b) {tag[k]=mx[k]=x;return;}int mid=l+r>>1;
    	if(tag[k]) pshd(k);
    	if(a<=mid) mdf(k<<1,l,mid,a,b,x);
    	if(b>mid) mdf(k<<1|1,mid+1,r,a,b,x);
    	mx[k]=max(mx[k<<1],mx[k<<1|1]);
    }
    int query(int k,int l,int r,int a,int b)
    {
    	if(a<=l&&r<=b) return mx[k];int mid=l+r>>1,res=0;
    	if(tag[k]) pshd(k);
    	if(a<=mid) res=max(res,query(k<<1,l,mid,a,b));
    	if(b>mid) res=max(res,query(k<<1|1,mid+1,r,a,b));
    	return res;
    }
    inline int getmx(int x,int ww)
    {
    	int res=0;dwn(i,19,0) if(ww&(1<<i))
    		res=max(res,fmx[x][i]),x=ff[x][i];
    	return res;
    }
    inline int getfa(int x,int ww)
    {
    	dwn(i,19,0) if(ww&(1<<i))
    		x=ff[x][i];
    	return x;
    }
    int solve(int x,int y,int res=0)
    {
    	for(;bl[x]!=bl[y];y=fa[bl[y]])
    		res=max(res,query(1,1,n,in[bl[y]],in[y]));
    	res=max(res,query(1,1,n,in[x],in[y]));
    	return res;
    }
    void work(int x,int y,int z)
    {
    	for(;bl[x]!=bl[y];y=fa[bl[y]])
    		mdf(1,1,n,in[bl[y]],in[y],z);
    	if(in[x]<in[y]) mdf(1,1,n,in[x]+1,in[y],z);
    }
    int main()
    {
    	int a,b;bl[0]=1;rep(T,1,read())
    	{
    		n=read();rep(i,1,n) fst[i]=0;dfn=cnt=0;
    		rep(i,2,n) a=read(),b=read(),add(a,b),add(b,a);
    		rep(i,1,n) w[i]=h[i]=read();sort(h+1,h+n+1);
    		rep(i,1,n) w[i]=lower_bound(h+1,h+n+1,w[i])-h,g[i]={w[i],i};
    		sort(g+1,g+n+1);
    		dfs(1,1);Dfs(1,1);
    		rep(i,1,n)
    		{
    			int l=1,r=dep[i],res=dep[i]+1,mid=l+r>>1;
    			for(;l<=r;mid=l+r>>1)
    				if(getmx(i,mid)>w[i]) res=mid,r=mid-1;
    				else l=mid+1;
    			if(res==dep[i]+1) st[i]=0;else st[i]=getfa(i,res);
    		}
    		build(1,1,n);
    		int x;dwn(i,n,1)
    		{
    			x=g[i].se;
    			ans[x]=solve(st[x],x)+1;
    			work(st[x],x,ans[x]);
    		}
    		rep(i,1,n) printf("%d
    ",ans[i]);
    	}
    }
    
  • 相关阅读:
    bootstrap-datetimepicker使用记录
    Highcharts使用====一些问题记录
    值类型 引用类型
    java 发送邮件
    包括post,get请求(http,https)的HttpClientUtils
    整理的java的日期DateUtil
    oracle随机取数据
    oracle查询表的索引
    有关dwr推送的笔记
    java 超经漂亮验证码
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/15399201.html
Copyright © 2011-2022 走看看