Codeforces Round 969 (Div. 1) 题解

24 篇文章 0 订阅
6 篇文章 0 订阅

A. Iris and Game on the Tree

题意:给定一棵树,点权为0或1。定义一个叶子的权值为:考虑从根到叶子的这条路径的点权组成的字符
串,权值为其中01作为连续子串出现次数减去10作为连续子串出现次数。定义树的价值为:权值非零
的叶子个数(不包括root节点1)。现在一些点权变成 ?,博弈的两人分别填充,先手最大化,后手最小化树的价值。求最终树的价值。
解法:一条路径计入答案当且仅当叶子和根权值不同。所以只和根和叶子的权值有关。若根的权值确
定,则策略显然;若根的权值不确定,一个思路是看叶子节点填过的0和1哪个多,按自己的目标填;实
际上当叶子节点的0和1个数相同时会出错:先填根的人必然会亏,所以此时先填非根非叶子节点,考虑
其问号个数的奇偶性即可。需要考虑多余的?能让先手交换先后手。

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<<a[i][j]<<' ';\
						cout<<a[i][m]<<endl; \
						} 
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 

#define MAXN (200000+10)

ll n,p[MAXN];
vi v[MAXN];
int c[MAXN]={}; //0
int t_stamp=0;
int d[MAXN][2];
void dfs(int x,int fa) {
	for (auto u:v[x])
		if (u!=fa) {
			dfs(u,x);
	}
	
}
char s[MAXN];
int main()
{
//	freopen("B.in","r",stdin);
//	freopen(".out","w",stdout);
	
	int tt=read();
	while(tt--) {
		n=read();
		For(i,n-1) {
			int x=read(),y=read();
			v[x].pb(y); v[y].pb(x);
		}
		cin>>(s+1);
		int a=0,b=0,c=0;
		Fork(i,2,n) if(SI(v[i])==1) {
			if(s[i]=='1') ++a;
			else if(s[i]=='0') ++b;
			else ++c;
		}
		int p=0;
		Fork(i,2,n) if(SI(v[i])!=1) p+=s[i]=='?';
		if(p%2==1) {
			if(s[1]=='?' && a==b) cout<<a+(c+1)/2<<endl;
			else if(s[1]=='?') cout<<max(a,b)+c/2<<endl;
			else if(s[1]=='1') cout<<b+(c+1)/2<<endl;
			else cout<<a+(c+1)/2<<endl;
				
		}
		else {
		if(s[1]=='?') cout<<max(a,b)+c/2<<endl;
		else if(s[1]=='1') cout<<b+(c+1)/2<<endl;
		else cout<<a+(c+1)/2<<endl;
		}
		For(i,n) v[i].resize(0);
		
	}
	
	return 0;
}


B. Iris and the Tree

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<<a[i][j]<<' ';\
						cout<<a[i][m]<<endl; \
						} 
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 

#define MAXN (200000+10)

ll n,p[MAXN];
vi v[MAXN];
int c[MAXN]={}; //0
int t_stamp=0;
int d[MAXN][2];
void dfs(int x,int fa) {
	++t_stamp;
	for (auto u:v[x]){
		// x->u
		c[t_stamp]++;
		d[u][0]=t_stamp;
		dfs(u,x);
		c[t_stamp]++;
		d[u][1]=t_stamp;
	}

}
ll x[MAXN],y[MAXN];
int main()
{
	freopen("A.in","r",stdin);
//	freopen(".out","w",stdout);
	
	int tt=read();
	while(tt--) {
		n=read();
		ll W;cin>>W;
		ll ans=0;
		Fork(i,2,n) {
			p[i]=read();
			v[p[i]].pb(i);
		}
		For(i,n) c[i]=0;
		t_stamp=0;
		dfs(1,-1);
		int z=n;
		ll s=0;
		For(i,n-1) {
			x[i]=read();
			cin>>y[i];
			s+=y[i];
			Rep(j,2) {
				int px=d[x[i]][j];
				c[px]--;
				if(c[px]==0) --z; 
			}
			cout<<s*2 + (W-s) * z;
			if(i==n-1) cout<<endl;else cout<<' ';
		}
		For(i,n) v[i].resize(0);
		
	}
	
	return 0;
}


C. Eri and Expanded Sets

题意:定义一个正整数集合是合法的:你可以任意次取出集合中的正整数 x,y,满足同奇偶性,且 ( x + y ) / 2 (x+y)/2 (x+y)/2
不在集合中,然后把它加入集合。做到无法再做为止,最终集合内的数必须连续。给定序列,求有
多少个子区间内的数组成的集合是合法的。

解法:考虑做差分:操作比较抽象,考虑结束条件:所有差分必须都是奇数(偶数可拆),且都相同
(可合并)。于是得到公差为奇数的等差数列。显然公差为所有差分的gcd除去所有2因子后的答案。
这个gcd等于不排序的邻项 ,显然有单调性,线段树+二分。

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<<a[i][j]<<' ';\
						cout<<a[i][m]<<endl; \
						} 
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 
int gcd(int a,int b){
	if(!b) return a; return gcd(b,a%b);
}
const int maxn =400000+10;
int sum[maxn<<2],a[maxn];
void pushup(int o) {
	sum[o]=gcd(sum[Lson],sum[Rson]);
}
void build(int l,int r,int o) {
	if (l==r) {
		sum[o]=a[l];	return ;
	}
	int m=(l+r)>>1;
	build(l,m,Lson),build(m+1,r,Rson);
	pushup(o);
}
int query(int l,int r,int o,int L,int R) {
	if(L<=l && r<=R ) return sum[o];
	int m=(l+r)>>1;
	int ret=0;
	if(L<=m) ret=gcd(ret,query(l,m,Lson,L,R));
	if(m<R) ret=gcd(ret,query(m+1,r,Rson,L,R)); 
	return ret;
}
int main()
{
	freopen("C.in","r",stdin);
//	freopen(".out","w",stdout);
	int tt=read();
	while(tt--) {
		int n=read();
		ll An=n;
		For(i,n) a[i]=read();
		For(i,n-1) a[i]=abs(a[i+1]-a[i]);
		build(1,n,1);
		
		For(i,n-1) {
			int l=i,r=n-1,ans=-1;
			while(l<=r) {
				int m=l+r>>1;
				int p=query(1,n,1,i,m);
				while(p!=0&&p%2==0) p/=2;
				if(p==1) ans=m,r=m-1;else l=m+1;
			}	
			if(ans!=-1) An+=n-ans;
//			cout<<i<<' '<<ans<<endl;
		}
		int p=0;
		For(i,n-1){
			if(a[i]==0) ++p,An+=p;
			else p=0;
		}
		cout<<An<<endl;
	}
	
	return 0;
}


D. Iris and Adjacent Products

题意:对于一个序列,你可以做单点修改(任何时刻值域都是[1,k] )或序列重排。定义权值为最小的单
点修改次数使得任意相邻两个数的乘积不超过 。区间查询权值。

解法:考虑最优的重排方式,先放最大值,然后最小值,然后次大值等等地交替放。证明考虑各种交换
证明更优性。于是序列合法当且仅当每个i大值和i小值的乘积都不超过 K。
设c(l,r) 表示值域在[l,r]的值的个数。考虑转化:对于每个 i < s q r t ( k ) i<sqrt(k) i<sqrt(k) ,都有 c n t ( 1 , i ) ≥ c n t ( n / i , n ) cnt(1,i) \ge cnt(n/i,n) cnt(1,i)cnt(n/i,n)
。这个 cnt本质不同只有 2 s q r t ( k ) 2sqrt(k) 2sqrt(k)个,暴力前缀和求出来,然后列个式子就好了(修改显然是把max 改成1
,这是容易的),需要注意长度为奇数时最中间一项不需要考虑。
离线莫队询问,复杂度 O ( ( n + q ) n + q k ) O((n+q)\sqrt{n} + q\sqrt{k}) O((n+q)n +qk )

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,0x3f,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define MEMx(a,b) memset(a,b,sizeof(a));
#define INF (0x3f3f3f3f)
#define F (1000000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
						For(j,m-1) cout<<a[i][j]<<' ';\
						cout<<a[i][m]<<endl; \
						} 
#pragma comment(linker, "/STACK:102400000,102400000")
#define ALL(x) (x).begin(),(x).end()
#define gmax(a,b) a=max(a,b);
#define gmin(a,b) a=min(a,b);
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
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;
} 
#define MAXN (100000+10)
#define N (100000)
bitset<100000> f,g;
int b[MAXN],res[MAXN],belong[MAXN],cnt[MAXN]={},cnt2[MAXN]={};
struct node{
	int l,r,id;
	friend bool operator<(node a,node b) {
		if (belong[a.l] ^ belong[b.l] )
			return belong[a.l] < belong[b.l];
		return a.r<b.r; 
	}
}a[MAXN];
int main()
{
//	freopen("D.in","r",stdin);
//	freopen(".out","w",stdout);
	int tt=read();
	while(tt--) {
		int n=read(),m=read();
		ll k=read();
		ll KS=sqrt(k);
		int BS=sqrt(n);
	    For(i,n)
			b[i]=read();
		For(i,m){
	        a[i]=node{read(),read(),i};
	    }
		For(i,n)
			belong[i]=(i-1)/BS+1;
		sort(a+1,a+m+1);
		int l=1,r=0;
	    For(i,KS) cnt[i]=cnt2[i]=0;
		For(i,m){
	        while(l>a[i].l){
	        	l--;
				if(b[l]<=KS) cnt[b[l]]++; else cnt2[k/b[l]]++;
	        }while(r<a[i].r){
	            r++;
				if(b[r]<=KS) cnt[b[r]]++; else cnt2[k/b[r]]++;
	        }while(l<a[i].l){
				if(b[l]<=KS) cnt[b[l]]--; else cnt2[k/b[l]]--;
				l++;
	        }while(r>a[i].r){
				if(b[r]<=KS) cnt[b[r]]--; else cnt2[k/b[r]]--;
				r--;
	        }
	        int ans=0;
	        int psmall=0,pbig=0;
	        For(i,KS) {
	        	if(psmall==0 && pbig==1 && cnt[i]+	cnt2[i]>0) {
	        		psmall++,pbig--;++ans;
				}
				psmall+=cnt[i];
	        	pbig+=cnt2[i];
	        	int t=min(psmall,pbig);
	        	psmall-=t,pbig-=t;
	        	if(pbig>psmall) {
	        		ans+=pbig/2;
	        		pbig%=2;
				}
			}
	        res[a[i].id]=ans;
	    }
		PRi(res,m)
	}
	
	
	return 0;
}


  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,Codeforces Round 511 (Div. 1)是一个比赛的名称。然而,引用内容中没有提供与这个比赛相关的具体信息或问题。因此,我无法回答关于Codeforces Round 511 (Div. 1)的问题。如果您有关于这个比赛的具体问题,请提供更多的信息,我将尽力回答。 #### 引用[.reference_title] - *1* [Codeforces Round 860 (Div. 2)题解](https://blog.csdn.net/qq_60653991/article/details/129802687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces Round 867 (Div. 3)(A题到E题)](https://blog.csdn.net/wdgkd/article/details/130370975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Codeforces Round 872 (Div. 2)(前三道](https://blog.csdn.net/qq_68286180/article/details/130570952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值