ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Educational Codeforces Round 110

2021-06-05 20:37:10  阅读:174  来源: 互联网

标签:Educational int ll Codeforces long typedef 110 printf define


比赛链接:https://codeforces.com/contest/1535
懒得一题一题写博客了。直接扔在一起吧(

A. Fair Playoff

题目链接:https://codeforces.com/contest/1535/problem/A

直接模拟。

#include <bits/stdc++.h>
#define pYES printf("YES\n");
#define pYes printf("Yes\n");
#define pyes printf("yes\n");
#define pNO printf("NO\n");
#define pNo printf("No\n");
#define pno printf("no\n");
#define mp make_pair
#define ST first
#define ND second
using namespace std;
typedef long long ll;
typedef long double ld;

const int N=200010;
int Q,a[5],b,c,d;

void work()
{
	scanf("%d%d%d%d",&a[1],&a[2],&a[3],&a[4]);
	int e=max(a[1],a[2]),f=max(a[3],a[4]);
	if (e<f) swap(e,f);
	sort(a+1,a+5);
	if (e==a[4] && f==a[3]) pYES
		else pNO
}

int main()
{
//	freopen("data.txt","r",stdin);
	scanf("%d",&Q);
	while (Q--) work();
	return 0;
}

B. Array Reodering

题目链接:https://codeforces.com/contest/1535/problem/B

考虑两个元素 \(x,y\):

  • 如果 \(\gcd(x,y)>1\),那么无论顺序都有 \(1\) 的贡献。
  • 如果 \(\gcd(x,y)=1\),且 \(x,y\) 有一个是偶数,让偶数排在前面就会有 \(1\) 的贡献。
  • 如果 \(\gcd(x,y)=1\),且 \(x,y\) 均为奇数,无论顺序都没有贡献。

枚举一下即可。

#include <bits/stdc++.h>
#define pYES printf("YES\n");
#define pYes printf("Yes\n");
#define pyes printf("yes\n");
#define pNO printf("NO\n");
#define pNo printf("No\n");
#define pno printf("no\n");
#define mp make_pair
#define ST first
#define ND second
using namespace std;
typedef long long ll;
typedef long double ld;

const int N=200010;
int Q,n,m,a[N],b[N];

void work()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	int ans=0;
	for (int i=1;i<=n;i++)
		for (int j=i+1;j<=n;j++)
		{
			if (__gcd(a[i],a[j])!=1) ans++;
				else if (!(a[i]&1) || !(a[j]&1)) ans++;
		}
	cout<<ans<<"\n";
}

int main()
{
//	freopen("data.txt","r",stdin);
	scanf("%d",&Q);
	while (Q--) work();
	return 0;
}

C. Unstable String

题目链接:https://codeforces.com/contest/1535/problem/C

考虑每一个极长合法区间 \([l,r]\),它的贡献就是 \(\frac{(r-l+1)(r-l+2)}{2}\)。
双指针找到所有区间后再减一下相邻区间中 ? 的贡献即可。

#include <bits/stdc++.h>
#define pYES printf("YES\n");
#define pYes printf("Yes\n");
#define pyes printf("yes\n");
#define pNO printf("NO\n");
#define pNo printf("No\n");
#define pno printf("no\n");
#define mp make_pair
#define ST first
#define ND second
using namespace std;
typedef long long ll;
typedef long double ld;

const int N=200010;
int Q,n,m,pos[N];
char s[N];

void work()
{
	ll ans=0;
	scanf("%s",s+1);
	n=strlen(s+1); m=0;
	for (int i=1;i<=n;i++)
		if (s[i]!='?') pos[++m]=i;
	if (!m) { cout<<1LL*n*(n+1)/2LL<<"\n"; return; }
	pos[m+1]=n+1;
	for (int i=1,j;i<=m;i=j+1)
	{
		j=i;
		while (j<m && ((pos[j+1]-pos[i])&1)==(s[pos[i]]!=s[pos[j+1]])) j++;
		int c=(pos[j+1]-1)-(pos[i-1]+1)+1;
		ans+=1LL*c*(c+1)/2LL;
		if (i>1)
		{
			c=pos[i]-pos[i-1]-1;
			ans-=1LL*c*(c+1)/2LL;
		}
	}
	cout<<ans<<"\n";
}

int main()
{
//	freopen("data.txt","r",stdin);
	scanf("%d",&Q);
	while (Q--) work();
	return 0;
}

D. Playoff Tournament

题目链接:https://codeforces.com/contest/1535/problem/D

下文 \(n\) 即为题目中的 \(k\)。
先把题目中编号为 \(x\) 的比赛编号改为 \(2^n-x\)。
记 \(f[i]\) 表示比赛 \(i\) 为根的子树内,能赢到 \(i\) 的队伍数量。不难发现

\[f[i]=\left\{\begin{matrix}f[2i+1]\ (s[i]=0) \\f[2i]\ (s[i]=1) \\f[2i]+f[2i+1]\ (s[i]=?) \end{matrix}\right. \]

注意叶子节点需要初始化。
每次修改只会修改一个点到根的路径的 \(f\),由于树高是 \(O(n)\) 的,所以每次修改都可以 \(O(n)\) 解决。
时间复杂度 \(O(Qn)\)。

#include <bits/stdc++.h>
#define pYES printf("YES\n");
#define pYes printf("Yes\n");
#define pyes printf("yes\n");
#define pNO printf("NO\n");
#define pNo printf("No\n");
#define pno printf("no\n");
#define mp make_pair
#define ST first
#define ND second
using namespace std;
typedef long long ll;
typedef long double ld;

const int N=300010;
int Q,n,m,f[N];
char s[N];

int main()
{
//	freopen("data.txt","r",stdin);
	scanf("%d",&n); n=(1<<n)-1;
	scanf("%s",s+1);
	for (int i=n;i>=1;i--)
	{
		if (i*2>n) { f[i]=1+(s[n-i+1]=='?'); continue; }
		if (s[n-i+1]=='?') f[i]=f[i*2]+f[i*2+1];
		if (s[n-i+1]=='0') f[i]=f[i*2+1];
		if (s[n-i+1]=='1') f[i]=f[i*2];
	}
	scanf("%d",&Q);
	while (Q--)
	{
		int x; char c[3];
		scanf("%d%s",&x,c);
		s[x]=c[0];	x=n-x+1;
		for (int i=x;i;i>>=1)
		{
			if (i*2>n) { f[i]=1+(s[n-i+1]=='?'); continue; }
			if (s[n-i+1]=='?') f[i]=f[i*2]+f[i*2+1];
			if (s[n-i+1]=='0') f[i]=f[i*2+1];
			if (s[n-i+1]=='1') f[i]=f[i*2];
		}
		cout<<f[1]<<"\n";
	}
	return 0;
}

E. Gold Transfer

题目链接:https://codeforces.com/contest/1535/problem/E

由于强制在线加点询问,所以几乎不用考虑什么数据结构维护了(定期重构除外)。
显然一次询问中是要不断取给定点到根中深度最小的且剩余物品的点购买。但是如果我们从根节点出发,并不好得知到给定点的路径。所以考虑从给定点出发找第一个能选的点。
那么显然直接倍增就可以了。由于一个点只会被删除一次,所以倍增次数是 \(O(Q)\) 的。

#include <bits/stdc++.h>
#define pYES printf("YES\n");
#define pYes printf("Yes\n");
#define pyes printf("yes\n");
#define pNO printf("NO\n");
#define pNo printf("No\n");
#define pno printf("no\n");
#define mp make_pair
#define ST first
#define ND second
using namespace std;
typedef long long ll;
typedef long double ld;

const int N=300010,LG=20;
int Q,n,m,rt=N-1,a[N],b[N],f[N][LG+1];

int find(int x)
{
	for (int i=LG;i>=0;i--)
		if (a[f[x][i]]) x=f[x][i];
	return x;
}

int main()
{
//	freopen("data.txt","r",stdin);
	scanf("%d%d%d",&Q,&a[N-2],&b[N-2]);
	for (int i=1;i<=Q;i++)
	{
		int opt;
		scanf("%d",&opt);
		if (opt==1)
		{
			scanf("%d%d%d",&f[i][0],&a[i],&b[i]);
			if (!f[i][0]) f[i][0]=N-2;
			for (int j=1;j<=LG;j++)
				f[i][j]=f[f[i][j-1]][j-1];
		}
		else
		{
			int w,x; ll ans=0,cnt=0;
			scanf("%d%d",&x,&w);
			if (!x) x=N-2;
			while (w)
			{
				if (!a[x]) break;
				int p=find(x);
				if (w>=a[p])
					ans+=1LL*a[p]*b[p],cnt+=a[p],w-=a[p],a[p]=0;
				else
					ans+=1LL*w*b[p],cnt+=w,a[p]-=w,w=0;
			}
			cout<<cnt<<' '<<ans<<"\n";
			fflush(stdout);
		}
	}
	return 0;
}

F. String Distance

题目链接:https://codeforces.com/contest/1535/problem/F

根号分治(听说应该叫平衡规划?)。感觉不是正解。
记 \(n\) 为字符串数量,\(m\) 为字符串长度。
设定一个阈值 \(Lim\)。

  • 对于 \(n\leq Lim\) 的点,我们可以直接枚举两个字符串,找到他们 LCP 和 LCS,然后中间的一部分可以暴力判断能否一次搞定。时间复杂度 \(O(n^2m)\)。
  • 对于 \(n>Lim\) 的点,我们把所有字符串排序,使得所有字符的出现次数都相等的字符串排在一起。然后对于一个所有字符出现次数都相等的区间 \([l,r]\),先把它和区间外的贡献求出来,然后枚举区间内的所有字符串,再枚举一个进行操作的区间 \([i,j]\),暴力把这个字符串的区间 \([i,j]\) 排序后二分一下是否有相等的字符串即可。时间复杂度 \(O(nm^3\log m)\)。

取 \(Lim=4000\) 就可以过了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=200010,Lim=4000;
int n,len,cnt[30];
char t[N];
vector<char> s[N];

bool check(int x,int y,int l=1,int r=len)
{
	memset(cnt,0,sizeof(cnt));
	for (int k=l;k<=r;k++)
		cnt[s[x][k]-'a']++,cnt[s[y][k]-'a']--;
	for (int i=0;i<26;i++)
		if (cnt[i]) return 0;
	return 1;
}

namespace S1
{
	bool check1(int x,int l,int r)
	{
		for (int i=l+1;i<=r;i++)
			if (s[x][i]<s[x][i-1]) return 0;
		return 1;
	}
	
	void main()
	{
		ll ans=0;
		for (int i=1;i<=n;i++)
			for (int j=i+1;j<=n;j++)
				if (check(i,j))
				{
					int k=1,l=len;
					while (s[i][k]==s[j][k]) k++;
					while (s[i][l]==s[j][l]) l--;
					if (check(i,j,k,l) && (check1(i,k,l) || check1(j,k,l))) ans++;
						else ans+=2;
				}
				else ans+=1337;
		cout<<ans;
	}
}

namespace S2
{
	int c1[30],c2[30];
	vector<char> t;
	
	bool cmp(vector<char> x,vector<char> y)
	{
		memset(c1,0,sizeof(c1));
		memset(c2,0,sizeof(c2));
		for (int i=1;i<=len;i++)
			c1[x[i]-'a']++,c2[y[i]-'a']++;
		for (int i=0;i<26;i++)
			if (c1[i]!=c2[i]) return c1[i]<c2[i];
		for (int i=1;i<=len;i++)
			if (x[i]!=y[i]) return x[i]<y[i];
		return 19260817;
	}
	
	bool find(int l,int r)
	{
		while (l<=r)
		{
			int mid=(l+r)>>1;
			bool flag=1;
			for (int i=1;i<=len;i++)
			{
				if (s[mid][i]<t[i]) { flag=0; l=mid+1; break; }
				if (s[mid][i]>t[i]) { flag=0; r=mid-1; break; }
			}
			if (flag) return 1;
		}
		return 0;
	}
	
	void main()
	{
		ll ans=0,ans1=0;
		sort(s+1,s+1+n,cmp);
		for (int l=1,r=1;l<=n;l=r=r+1)
		{
			while (r<n && check(l,r+1)) r++;
			ans1+=1337LL*(r-l+1)*(n-(r-l+1));
			ll res=0;
			for (int i=1;i<=len;i++)
				for (int j=i+1;j<=len;j++)
					for (int k=l;k<=r;k++)
					{
						t=s[k];
						sort(t.begin()+i,t.begin()+j+1);
						if (t[i]!=s[k][i] && t[j]!=s[k][j] && find(l,r)) res++;
					}
			ans+=1LL*(r-l+1)*(r-l)-res;
		}
		cout<<ans+ans1/2LL;
	}
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%s",t+1);
		if (i==1) len=strlen(t+1);
		for (int j=0;j<=len;j++)
			s[i].push_back(t[j]);
	}
	if (n<=Lim) S1::main();
		else S2::main();
	return 0;
}

标签:Educational,int,ll,Codeforces,long,typedef,110,printf,define
来源: https://www.cnblogs.com/stoorz/p/14853756.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有