CR 952 (Div. 4)

前言

        非比赛题解,Div 4 感觉没什么好说的。

        题目连接:Dashboard - Codeforces Round 952 (Div. 4) - Codeforces

A. Creating Words

        略。

#include<cstdio>
#include<cstring>
using namespace std;

int T;
char a[5],b[5];

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%s%s",a + 1,b + 1);
		char s = a[1];
		a[1] = b[1],b[1] = s;
		printf("%s %s\n",a + 1,b + 1);
	}
	return 0;
}

B. Maximum Multiple Sum

        略。

#include<cstdio>
#include<cstring>
using namespace std;

int T,x,y,z;
long long k,ans;

long long max(long long x,long long y) { return x > y ? x : y ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d%d%lld",&x,&y,&z,&k),ans = 0ll;
		for (int a = 1;a <= x;++ a)
			if(!(k % a))
				for (int b = 1;b <= y;++ b)
					if(!(k % (a * b)))
					{
						long long c = k / (long long)(a * b);
						if(!c || c > z) continue;
						ans = max(ans,(long long)(x - a + 1ll) * (y - b + 1ll) * (z - c + 1ll));
					}
		printf("%lld\n",ans);
	}
	return 0;
}

C. Good Prefixes

        略。

#include<cstdio>
#include<cstring>
using namespace std;

int T,n,ans;
long long sum,mx,a;

long long max(long long x,long long y) { return x > y ? x : y ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d",&n),ans = sum = mx = 0;
		for (int i = 1;i <= n;++ i)
		{
			scanf("%lld",&a);
			sum += a;
			mx = max(mx,a);
			if(mx == sum - mx) ++ ans;
		}
		printf("%d\n",ans);
	}
	return 0;
}

D. Manhattan Circle

        略。

#include<cstdio>
#include<cstring>
using namespace std;

int T,n,m;
long long tot,sx,sy;
char s;

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d",&n,&m),tot = sy = sx = 0ll;
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= m;++ j)
			{
				s = getchar();
				while (s != '.' && s != '#') s = getchar();
				tot += (s == '#'),sy += (s == '#') * i,sx += (s == '#') * j;
			}
		printf("%lld %lld\n",sy / tot,sx / tot);
	}
	return 0;
}

E. Secret Box

        略。

#include<cstdio>
#include<cstring>
using namespace std;

int T,x,y,z;
long long k,ans;

long long max(long long x,long long y) { return x > y ? x : y ; }

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d%d%lld",&x,&y,&z,&k),ans = 0ll;
		for (int a = 1;a <= x;++ a)
			if(!(k % a))
				for (int b = 1;b <= y;++ b)
					if(!(k % (a * b)))
					{
						long long c = k / (long long)(a * b);
						if(!c || c > z) continue;
						ans = max(ans,(long long)(x - a + 1ll) * (y - b + 1ll) * (z - c + 1ll));
					}
		printf("%lld\n",ans);
	}
	return 0;
}

F. Final Boss

        二分。

#include<cstdio>
#include<cstring>
using namespace std;

#define N 200005

int T,h,n,a[N],c[N];
long long ans;

int check(long long x)
{
	long long tmp = 0ll;
	for (int i = 1;i <= n;++ i)
	{
		tmp += 1ll * ((x - 1ll) / c[i] + 1ll) * a[i];
		if(tmp >= h) return 1;
	}
	return 0;
}

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d",&h,&n),ans = 0ll;
		for (int i = 1;i <= n;++ i) scanf("%d",&a[i]);
		for (int i = 1;i <= n;++ i) scanf("%d",&c[i]);
		long long l,r,mid;
		l = 1,r = 40000000009;
		while (l <= r)
		{
			mid = (l + r) >> 1;
			if(check(mid)) ans = mid,r = mid - 1;
			else l = mid + 1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

G. D-Function

        简单思维题。

        假设原数字的某一位为 m ,则必须满足 k*m < 10 ,即不能进位的意思,那么我们只需要求出 m 可能的最大值就可以快速幂计数了。

#include<cstdio>
#include<cstring>
using namespace std;

#define mod 1000000007

int T,l,r,k,p;
long long ans;

long long pow(long long x,int k)
{
	long long tmp = 1ll;
	while (k)
	{
		if(k & 1) tmp = tmp * x % mod;
		k >>= 1;
		x = x * x % mod;
	}
	return tmp;
}

long long tot(int x)
{
	if(!x) return 1ll;
	return 1ll * pow(p + 1ll,x) % mod;
}

int main()
{
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d%d",&l,&r,&k);
		if(k > 9)
		{
			printf("0\n");
			continue;
		}
		p = 0;
		while (k * (p + 1) < 10) ++ p;
		ans = ((tot(r) - tot(l)) % mod + mod) % mod;
		printf("%lld\n",ans);
	}
	return 0;
}

H1. Maximize the Largest Component (Easy Version)

        用并查集(dfs也可以)统计每个连通块的大小,暴力枚举每一行,那么每一行的贡献就是这一行上的 "." 的数目加上与其相邻的行上连通块的大小之和。列的道理是一样,求最大值即可。

#include<cstdio>
#include<cstring>
using namespace std;

#define N 1000006

int T,n,m,a[N],fa[N],siz[N],vis[N],bz[N],cnt,ans;

int get(int x,int y) { return (x - 1) * m + y ; }

int max(int x,int y) { return x > y ? x : y ; }

int find(int x)
{
	if(fa[x] != x) fa[x] = find(fa[x]);
	return fa[x];
}

int main()
{
	memset(a,0,sizeof a);
	memset(fa,0,sizeof fa);
	memset(siz,0,sizeof siz);
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d",&n,&m),ans = 0;
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= m;++ j)
			{
				int tmp = get(i,j);
				char s;
				scanf(" %c",&s);
				a[tmp] = (s == '.') ? 0 : 1,fa[tmp] = tmp,siz[tmp] = 1,vis[tmp] = 0;
				if(!a[tmp]) continue;
				ans = 1;
				int nor = get(i - 1,j);
				int wes = get(i,j - 1);
				if(i > 1 && a[nor]) siz[find(nor)] += siz[find(tmp)],fa[find(tmp)] = find(nor),ans = max(ans,siz[find(nor)]);
				if(j > 1 && a[wes] && find(tmp) != find(wes)) siz[find(wes)] += siz[find(tmp)],fa[find(tmp)] = find(wes),ans = max(ans,siz[find(wes)]);
			}
		for (int i = 1;i <= n;++ i)
		{
			cnt = 0;
			int tmp = 0;
			for (int j = 1;j <= m;++ j)
			{
				int now = get(i,j);
				int nor = get(i - 1,j);
				int sou = get(i + 1,j);
				tmp += (!a[now]);
				if(a[now] && !vis[find(now)]) vis[find(now)] = 1,tmp += siz[find(now)],bz[++ cnt] = find(now);
				if(i > 1 && a[nor] && !vis[find(nor)]) vis[find(nor)] = 1,tmp += siz[find(nor)],bz[++ cnt] = find(nor);
				if(i < n && a[sou] && !vis[find(sou)]) vis[find(sou)] = 1,tmp += siz[find(sou)],bz[++ cnt] = find(sou);
			}
			ans = max(ans,tmp);
			for (int j = 1;j <= cnt;++ j) vis[bz[j]] = 0;
		}
		for (int j = 1;j <= m;++ j)
		{
			cnt = 0;
			int tmp = 0;
			for (int i = 1;i <= n;++ i)
			{
				int now = get(i,j);
				int wes = get(i,j - 1);
				int eas = get(i,j + 1);
				tmp += (!a[now]);
				if(a[now] && !vis[find(now)]) vis[find(now)] = 1,tmp += siz[find(now)],bz[++ cnt] = find(now);
				if(j > 1 && a[wes] && !vis[find(wes)]) vis[find(wes)] = 1,tmp += siz[find(wes)],bz[++ cnt] = find(wes);
				if(j < m && a[eas] && !vis[find(eas)]) vis[find(eas)] = 1,tmp += siz[find(eas)],bz[++ cnt] = find(eas);
			}
			ans = max(ans,tmp);
			for (int i = 1;i <= cnt;++ i) vis[bz[i]] = 0;
		}
		printf("%d\n",ans);
	}
	return 0;
}

H2. Maximize the Largest Component (Hard Version)

        如果仍然按照 Easy Version 的做法,那么时间复杂度太大且不方便处理重合的部分,考虑另一种计数方法。

        既然直接求每一对行&列的贡献不行,那就思考每一个连通块能贡献到的行 / 列。

        假设每个连通块的上下左右界分别是:nor,sou,wes,eas,则它能贡献的行是:[nor - 1,sou + 1],它能贡献的列是:[wes - 1,eas + 1] 。于是对于每一个连通块,我们可以把它贡献的行列区间都先加上1,再考虑去重。

        对每个连通块,重复计算的贡献为 行 [nor - 1,sou + 1] 和列 [wes - 1,eas + 1] 配对的情况,即一个左上角为 (nor - 1,wes - 1),右下角为 (sou + 1,eas + 1) 的矩形,那么我们只需要再维护一个去重数组,对每个连通块的这部分重复矩形的贡献也加上1,最后计算答案的时候减去即可。

        为了在时间上更优秀,可以使用差分的方法。

        当然别忘了还有最后一部分贡献是枚举的行和列上 "." 的数目。

#include<cstdio>
#include<cstring>
using namespace std;

#define N 2000006

int T,n,m,a[N],fa[N],siz[N],nor[N],sou[N],wes[N],eas[N],vis[N],id[N],dr[N],dl[N],ds[N],l[N],r[N],s[N],fl[N],fr[N],cnt,ans;

int get(int x,int y) { return (x - 1) * m + y ; }

int min(int x,int y) { return x < y ? x : y ; }

int max(int x,int y) { return x > y ? x : y ; }

int find(int x)
{
	if(fa[x] != x) fa[x] = find(fa[x]);
	return fa[x];
}

int main()
{
	memset(a,0,sizeof a);
	memset(fa,0,sizeof fa);
	memset(siz,0,sizeof siz);
	scanf("%d",&T);
	while (T --)
	{
		scanf("%d%d",&n,&m),ans = 0;
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= m;++ j)
			{
				int tmp = get(i,j);
				char st;
				scanf(" %c",&st);
				a[tmp] = (st == '.') ? 0 : 1,fa[tmp] = tmp,siz[tmp] = 1,vis[tmp] = 0,nor[tmp] = sou[tmp] = i,wes[tmp] = eas[tmp] = j;
				if(!a[tmp]) continue;
				ans = 1;
				int tn = get(i - 1,j);
				int tw = get(i,j - 1);
				if(i > 1 && a[tn])
				{
					int rn = find(tn);
					siz[rn] += siz[tmp],fa[tmp] = rn,ans = max(ans,siz[rn]);
					sou[rn] = max(sou[rn],i);
				}
				if(j > 1 && a[tw] && find(tmp) != find(tw))
				{
					int rt = find(tmp);
					int rw = find(tw);
					siz[rw] += siz[rt],fa[rt] = rw,ans = max(ans,siz[rw]);
					nor[rw] = min(nor[rw],nor[rt]),eas[rw] = max(eas[rw],eas[rt]),wes[rw] = min(wes[rw],wes[rt]);
				}
			}
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= m;++ j)
				id[get(i,j)] = find(get(i,j));
		for (int i = 0;i <= n + 1;++ i)
		{
			r[i] = dr[i] = 0;
			for (int j = 0;j <= m + 1;++ j)
				l[j] = s[get(i,j)] = dl[j] = ds[get(i,j)] = 0;
		}
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= m;++ j)
			{
				int now = id[get(i,j)];
				if(!vis[now] && a[now])
				{
					vis[now] = 1;
					dr[max(nor[now] - 1,1)] += siz[now],dr[min(sou[now] + 2,n + 1)] -= siz[now];
					dl[max(wes[now] - 1,1)] += siz[now],dl[min(eas[now] + 2,m + 1)] -= siz[now];
					ds[get(max(nor[now] - 1,1),max(wes[now] - 1,1))] += siz[now],ds[get(min(sou[now] + 2,n + 1),min(eas[now] + 2,m + 1))] += siz[now];
					ds[get(max(nor[now] - 1,1),min(eas[now] + 2,m + 1))] -= siz[now],ds[get(min(sou[now] + 2,n + 1),max(wes[now] - 1,1))] -= siz[now];
				}
			}
		r[0] = l[0] = s[0] = 0;
		for (int i = 1;i <= n;++ i)
		{
			r[i] = r[i - 1] + dr[i],fr[i] = 0;
			for (int j = 1;j <= m;++ j) fr[i] += (!a[get(i,j)]);
		}
		for (int j = 1;j <= m;++ j)
		{
			l[j] = l[j - 1] + dl[j],fl[j] = 0;
			for (int i = 1;i <= n;++ i) fl[j] += (!a[get(i,j)]);
		}
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= m;++ j)
				s[get(i,j)] = s[get(i - 1,j)] + s[get(i,j - 1)] - s[get(i - 1,j - 1)] + ds[get(i,j)];
		for (int i = 1;i <= n;++ i)
			for (int j = 1;j <= m;++ j)
				ans = max(ans,r[i] + l[j] - s[get(i,j)] + fr[i] + fl[j] - (!a[get(i,j)]));
		printf("%d\n",ans);
	}
	return 0;
}

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值