等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(i−1)=∑i2−∑i=n(n+1)(2n+1)/6−n(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(i−1)=n∗(n+1)∗(2n+1)/6+(n−1)n(n+1)/3=n∗(4n−1)∗(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;
}