• Codeforces Forethought Future Cup Elimination Round 选做


    1146C Tree Diameter

    题意

    交互题。有一棵 (n(nle 100)) 个点的树,你可以进行不超过 (9) 次询问,每次询问两个点集中两个不在同一点集的点的最大距离。求树的直径。

    题解

    GXOI2019旅行者 基本类似,二进制分组,对于每一位,编号当前位为 (0) 的分到一组,当前位为 (1) 的分到另一组。最大询问次数为 (log 100 = 7)

    code

    #include<cstdio>
    int v1[105],v2[105];
    int main()
    {
    	int T; scanf("%d",&T);
    	while(T--)
    	{
    		int n,ans=0; scanf("%d",&n);
    		for(int i=0;i<=6;++i)
    		{
    			int id1=0,id2=0;
    			for(int j=1;j<=n;++j) (j&(1<<i))?v1[++id1]=j:v2[++id2]=j;
    			if(id1&&id2)
    			{
    				printf("%d %d ",id1,id2);
    				for(int i=1;i<=id1;++i) printf("%d ",v1[i]);
    				for(int i=1;i<=id2;++i) printf("%d ",v2[i]);
    				puts(""); fflush(stdout);
    				int x; scanf("%d",&x);
    				if(x>ans) ans=x;
    			}
    		}
    		printf("-1 %d
    ",ans);
    		fflush(stdout);
    	}
    }
    

    1146D Frog Jumping

    题意

    有一条数轴,一只青蛙在原点,可以向前跳 (a) 步或向后跳 (b) 步。

    定义 (f(x)) 表示青蛙在 ([0,x]) 里跳,能跳到的点数。

    (sum_{i=0}^m f(i))(mle 10^9, a,ble 10^5)

    题解

    能到达的点 (c) 能被表示为 (ax-by=c)

    根据裴蜀定理,能到达的点一定是 (gcd(a,b)) 的倍数。

    但是,当 (i<a+b) 时,(f(i)) 由于跳的点不能超过 (i) ,有的点可能会无法跳到。故 (f(0)sim f(a+b)) 的答案我们要另外计算。

    我们考虑贪心的去跳,当跳的步数 (>b) 就减去 (b) 。暴力枚举 (i) 统计有多少个点能到达即可。

    注意不要重复统计答案。

    code

    #include<cstdio>
    int gcd(int x, int y) {
    	return y?gcd(y,x%y):x;
    }
    const int N=2e5+5;
    bool vis[N];
    int step[N],tot;
    int main()
    {
    #ifndef ONLINE_JUDGE
    	freopen("sol.in","r",stdin);
    #endif
    	int m,a,b;
    	scanf("%d%d%d",&m,&a,&b);
    	const int g=gcd(a,b);
    	long long ans=1ll*(1+m/g+1)*(m/g+1)/2ll*g-1ll*(1ll*(m/g+1)*g-m-1)*(m/g+1);
    	vis[step[++tot]=0]=true;
    	while(true)
    	{
    		++tot;
    		step[tot]=step[tot-1]>=b?step[tot-1]-b:step[tot-1]+a;
    		if(vis[step[tot]]) break;
    		vis[step[tot]]=true;
    	} --tot;
    	for(int i=0,j=1;i<a+b&&i<=m;++i)
    	{
    		ans-=i/g+1;
    		while(step[j]<=i&&j<=tot) ++j;
    		ans+=j-1;
    	}
    	printf("%lld",ans);
    }
    
    

    1146E Hot is Cold

    题意

    给你一个长度为 (n) 的序列和 (q) 个操作,每次操作将 (<x_i) 的取反或 (>x_i) 的数取反。求最后的序列。(n,qle 10^5)

    题解

    对正数和负数分别维护权值线段树,然后分类讨论维护每个数是否被取反的标记。

    考虑 (>x) :当 (x<0) :将绝对值 (>x) 的数置为负 ; 当 (x>0) ,将正负数绝对值 (<-x) 标记取反,绝对值 (ge -x) 的数置为负;

    (<x) 与上述类似。

    有神仙线性做法,待补充……

    code

    #include<cstdio>
    #include<cstring>
    inline int gi()
    {
    	char c=getchar(); int x=0,f=1;
    	for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
    	return x*f;
    }
    const int N=1e5+5;
    int st[2][N<<2],tg[2][N<<2],rev[2][N<<2],fg[2][N<<2],a[N],n,q,m;
    #define lx (x<<1)
    #define rx (x<<1|1)
    void pushdown(int i, int x)
    {
    	if(tg[i][x]!=-1)
    	{
    		tg[i][lx]=tg[i][rx]=st[i][lx]=st[i][rx]=tg[i][x];
    		tg[i][x]=-1;
    	}
    	if(fg[i][x])
    	{
    		fg[i][lx]=fg[i][rx]=1;
    		rev[i][lx]=rev[i][rx]=0;
    		fg[i][x]=0;
    	}
    	if(rev[i][x])
    	{
    		rev[i][lx]^=1,rev[i][rx]^=1;
    		st[i][lx]^=1,st[i][rx]^=1;
    		rev[i][x]=0;
    	}
    }
    void rever(int i, int x, int l, int r, int sl, int sr)
    {
    	if(sl>sr) return ;
    	if(sl<=l&&r<=sr) {
    		rev[i][x]^=1,st[i][x]^=1; return ;
    	}
    	pushdown(i,x);
    	int mid=l+r>>1;
    	if(sl<=mid) rever(i,lx,l,mid,sl,sr);
    	if(sr>mid) rever(i,rx,mid+1,r,sl,sr);
    }
    void update(int i, int x, int l, int r, int sl, int sr, int w)
    {
    	if(sl>sr) return ;
    	if(sl<=l&&r<=sr)
    	{
    		tg[i][x]=st[i][x]=w, rev[i][x]=0, fg[i][x]=1;
    		return ;
    	}
    	pushdown(i,x);
    	int mid=l+r>>1;
    	if(sl<=mid) update(i,lx,l,mid,sl,sr,w);
    	if(sr>mid) update(i,rx,mid+1,r,sl,sr,w);
    }
    int qry(int i, int x, int l, int r, int s)
    {
    	if(l==r) return st[i][x];
    	pushdown(i,x);
    	int mid=l+r>>1;
    	return (s<=mid?qry(i,lx,l,mid,s):qry(i,rx,mid+1,r,s));
    }
    int main()
    {
    	n=gi(),q=gi();
    	for(int i=1;i<=n;++i)
    	{
    		a[i]=gi();
    		if(a[i]>m) m=a[i];
    		if(-a[i]>m) m=-a[i];
    	}
    	memset(tg,-1,sizeof(tg));
    	while(q--)
    	{
    		char s[2]; scanf("%s",s);
    		int x=gi();
    		if(s[0]=='>')
    		{
    			if(x>0)
    			{
    				update(0,1,1,m,x+1,m,0);
    				update(1,1,1,m,x+1,m,1);
    			}
    			else
    			{
    				rever(0,1,1,m,1,-x-1);
    				update(0,1,1,m,-x,m,0);
    				rever(1,1,1,m,1,-x-1);
    				update(1,1,1,m,-x,m,1);
    			}
    		}
    		else
    		{
    			if(x<0)
    			{
    				update(0,1,1,m,-x+1,m,1);
    				update(1,1,1,m,-x+1,m,0);
    			}
    			else
    			{
    				rever(0,1,1,m,1,x-1);
    				update(0,1,1,m,x,m,1);
    				rever(1,1,1,m,1,x-1);
    				update(1,1,1,m,x,m,0);
    			}
    		}
    	}
    	for(int i=1;i<=n;++i)
    	{
    		if(a[i]==0) printf("0 ");
    		else if(a[i]<0) printf("%d ",a[i]*(qry(0,1,1,m,-a[i])?-1:1));
    		else printf("%d ",a[i]*(qry(1,1,1,m,a[i])?-1:1));
    	}
    }
    
    

    1146F Leaf Partition

    题意

    给你一棵 (n) 个节点的树,将叶子节点划分成若干个集合,使得每个集合的虚树互不相交。求划分方案数。

    (nle 2cdot 10^5)

    题解

    (f(u,0)) 表示 (u) 不属于任何集合的方案数。

    (f(u,1)) 表示 (u) 连通了 (1) 个子节点。显然,当前节点必须要连通到上面的集合。

    (f(u,2)) 表示 (u) 连通了 (2) 个以上的子节点。

    这样,对于子节点 (v) ,将其分到不同集合的方案数为 (f(v,0)+f(v,2)) ,设为 (x) ;将其分到同一集合的方案数为 (f(v,1)+f(v,2)) ,设为 (y)

    这样就不难得出转移:

    [egin{cases} f'(u,0)=f(u,0) imes x\ f'(u,1)=f(u,0) imes y+f(u,1) imes x \ f'(u,2)=f(u,1) imes y+f(u,2) imes (x+y) end{cases} ]

    code

    #include<cstdio>
    inline int gi()
    {
    	char c; int x=0;
    	for(;c<'0'||c>'9';c=getchar());
    	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
    	return x;
    }
    const int N=200005,Mod=998244353;
    int f[N][3],head[N],nxt[N],to[N],n;
    void addedge(int u, int v, int now) {
    	nxt[now]=head[u], head[u]=now, to[now]=v;
    }
    #define mul(x,y) (1ll*x*y%Mod)
    void dfs(int u)
    {
    	if(!head[u]) f[u][2]=1;
    	else f[u][0]=1;
    	for(int e=head[u];e;e=nxt[e])
    	{
    		int& v=to[e];
    		dfs(v);
    		int x=(f[v][0]+f[v][2])%Mod,y=(f[v][1]+f[v][2])%Mod;
    		int f0=mul(f[u][0],x);
    		int f1=(mul(f[u][0],y)+mul(f[u][1],x))%Mod;
    		int f2=(mul(f[u][1],y)+mul(f[u][2],(x+y)%Mod))%Mod;
    		f[u][0]=f0,f[u][1]=f1,f[u][2]=f2;
    	}
    }
    int main()
    {
    	n=gi();
    	for(int i=2;i<=n;++i)
    		addedge(gi(),i,i-1);
    	dfs(1);
    	printf("%d",(f[1][0]+f[1][2])%Mod);
    }
    
    
  • 相关阅读:
    .dll .h .lib等文件的作用与区别
    [转自]语言黑客的福音
    [转载]一个台湾程序员的心历路程
    Servlet学习总结
    会话跟踪(Cookie & Session)
    JSP学习总结
    人往高处走,水往低处流
    GDI 和GDI+ 混合编程
    常用到的知识
    Sqlite3相关
  • 原文地址:https://www.cnblogs.com/farway17/p/10752671.html
Copyright © 2020-2023  润新知