Codeforces Round #841 (Div. 2) and Divide by Zero 2022 A-D

等System test的时候顺便水一篇吧233,感觉题目挺好的,但是我C、D都快要调完了,还是难受。

应该是我参加的今年最后一场比赛了。

Codeforces Round #841 (Div. 2) and Divide by Zero 2022

A. Joey Takes Money

#include<bits/stdc++.h>
using namespace std;
int T,n;
long long ans=1;
int main()
{
	cin>>T;
	while(T--)
	{
		ans=1;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			long long x;
			scanf("%lld",&x);
			ans*=x;
		}
		ans+=(n-1);
		ans*=2022;
		cout<<ans<<endl;
	}
	return 0;
}

B. Kill Demodogs

∑ i 2 = n ( n + 1 ) ( 2 n + 1 ) / 6 ∑i^2 = n(n+1)(2n+1)/6 i2=n(n+1)(2n+1)/6

∑ i ( i − 1 ) = ∑ i 2 − ∑ i = n ( n + 1 ) ( 2 n + 1 ) / 6 − n ( n + 1 ) / 2 ∑i(i-1) = ∑i^2 -∑i = n(n+1)(2n+1)/6 -n(n+1)/2 i(i1)=i2i=n(n+1)(2n+1)/6n(n+1)/2

a n s = ∑ i 2 + ∑ i ( i − 1 ) = n ∗ ( n + 1 ) ∗ ( 2 n + 1 ) / 6 + ( n − 1 ) n ( n + 1 ) / 3 = n ∗ ( 4 n − 1 ) ∗ ( n + 1 ) / 6 ans =∑i^2+∑i(i-1) =n*(n+1)*(2n+1)/6+(n-1)n(n+1)/3=n*(4n-1)*(n+1)/6 ans=i2+i(i1)=n(n+1)(2n+1)/6+(n1)n(n+1)/3=n(4n1)(n+1)/6
注意取余。

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int T;
long long n,ans=337;//2022/6
int main()
{
	cin>>T;
	while(T--)
	{
		cin>>n;
		ans=337;
		ans*=n,ans%=mod;
		ans*=((4*n-1)%mod),ans%=mod;
		ans*=(n+1),ans%=mod;
		cout<<ans<<endl;
	}
	return 0;
}

C. Even Subarrays

统计(i,j)的异或和相当于求(i-1)(j)两个点的异或前缀和,暴力先行一发
在这里插入图片描述
这里最直接的思路就是枚举前面的,看哪些数对异或和是平方数

所以我们可以反过来枚举一个个平方数,看前面到目前为止有多少个数跟当前的x异或出来是平方数,注意平方数要枚举到2*n的大小,另外数组也要开大一点。
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=6e5+10;
int a[N],num[N];
int T,n,cnt;
int main()
{	
	cin>>T;
	while(T--)
	{
		cin>>n;
		memset(num,0,sizeof(num));
		long long ans=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			num[a[i-1]]++;
			a[i]^=a[i-1];//统计(i,j)的异或和相当于求(i-1)(j)两个点的异或前缀和
			for(int j=0;j*j<=2*n+2;j++)
				ans+=num[(j*j)^a[i]];
			//对于每个x,我们求0到(x-1)的异或前缀和值,看它们是不是平方数
			//反过来,我们枚举平方数
			//看看在[0,x-1]这个范围内有多少数满足跟x这个位置的数异或前缀和是平方数
		}
		cout<<1ll*n*(n+1)/2-ans<<endl;
	}
	return 0;
}

D. Valiant’s New Map

二分答案,用DP求二分到x时整个地图上满足条件的最大正方形边长,看是否超过x。

最处理不好的还是不知道N*M可以达到2e5情况的二维数组怎么开,我感觉我写的跟正解没有啥区别但是不知道为什么不过QAQ最离谱的还是样例在本地上跑(2 1 1 3,是对的)和提交上去的结果(2 1 2 4)不一样,这是为什么。。。
我的错误代码:

#include<bits/stdc++.h>
using namespace std;
int T,n,m;

int main()
{
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		int mp[n+5][m+5],dp[n+5][m+5];
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				scanf("%d",&mp[i][j]);
		int l=1,r=min(n,m);
		while(l<=r)
		{
			int mid=l+r>>1,maxn=0;
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=m;j++)
				{
					if(mp[i][j]<mid) dp[i][j]=0;
					else dp[i][j]=min({dp[i-1][j],dp[i][j-1],dp[i-1][j-1]})+1;
					maxn=max(maxn,dp[i][j]);
				}
			}
			if(maxn>=mid) l=mid+1;
			else r=mid-1;
		}
	}
	return 0;
}

正解:

#include <bits/stdc++.h>
using namespace std;
 
int N, M;
vector<int> A[1010101];
vector<int> D[1010101];
 
int main() 
{
	int tc; scanf("%d", &tc);
	while (tc--) 
	{
		scanf("%d%d", &N, &M);
		for (int i = 0; i <= N; i++) 
		{
			A[i].resize(M + 1);
			D[i].resize(M + 1);
		}
		for (int i = 1; i <= N; i++) 
			for (int j = 1; j <= M; j++) 
				scanf("%d", &A[i][j]);
		int l = 1, r = min(N, M);
		while (l <= r) 
		{
			int m = l + r >> 1;
			int mx = 0;
			for (int i = 1; i <= N; i++) 
			{
				for (int j = 1; j <= M; j++) 
				{
					if (A[i][j] < m) D[i][j] = 0;
					else D[i][j] = min({D[i - 1][j], D[i][j - 1], D[i - 1][j - 1]}) + 1;
					mx = max(mx, D[i][j]);
				}
			}
			if (mx >= m) l = m + 1;
			else r = m - 1;
		}
		printf("%d\n", r);
	}
	return 0;
}

更好理解的是这样用二维前缀和写的,先跑一遍全图标记。

bool check(int mid, VV a)
{
    VV pre(n + 1, V(m + 1));
    rep(i, 0, n)
    {
        rep(j, 0, m)
        {
            if (a[i][j] >= mid) a[i][j] = 1;
            else a[i][j] = 0;
            pre[i + 1][j + 1] = pre[i][j + 1] + pre[i + 1][j] - pre[i][j] + a[i][j];
        }
    }
    rep(i, mid, n + 1)
    {
        rep(j, mid, m + 1)
        {
            int sum = pre[i][j] - pre[i][j - mid] - pre[i - mid][j] + pre[i - mid][j - mid];
            if (sum == mid * mid) return true;
        }
    }
    return false;
}
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春弦_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值