7 .30 ACM总结

放假前几天,老师让我们打一场ACM来放松一下(非常好,放松不一定,被压力了)
C题
C题是个非常水的搜索题,队友看一眼就秒了。写的时候出了一点小问题,但也调出来了,此时我们来到了第6(总共7队)。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3 + 5;
ll n, m, ans;
string a[N];
//int fd(int x, int y){
//    int res = 0;
//    if(y+3<m&&a[x][y+1]==a[x][y+3]&&a[x][y+1]=='e'&&a[x][y]==a[x][y+2])++res;
//    if(y-3>-1&&a[x][y-1]==a[x][y-3]&&a[x][y-1]=='e'&&a[x][y]==a[x][y-2])++res;
//    if(x+3<=n&&a[x+1][y]==a[x+3][y]&&a[x+1][y]=='e'&&a[x][y]==a[x+2][y])++res;
//    if(x-3>0&&a[x-1][y]==a[x-3][y]&&a[x-1][y]=='e'&&a[x-2][y]==a[x][y])++res;
//    return res;
//}
int fd(int x, int y){
    int res = 0;
    if(y + 3 < m and a[x][y + 1] == a[x][y + 3] and a[x][y + 1] == 'e' and a[x][y] == a[x][y + 2])++res;
    if(y - 3 > - 1 and a[x][y - 1] == a[x][y - 3] and a[x][y - 1] == 'e' and a[x][y] == a[x][y - 2])++res;
    if(x + 3 <= n and a[x + 1][y] == a[x + 3][y] and a[x + 1][y] == 'e' and a[x][y] == a[x + 2][y])++res;
    if(x - 3 > 0 and a[x - 1][y] == a[x - 3][y] and a[x - 1][y] == 'e' and a[x][y] == a[x - 2][y])++res;
    return res;
}
signed main(){
    scanf("%lld%lld",&n,&m); 
    for(int i=1;i<=n;++i)cin>>a[i];
    for(int i=1;i<=n;++i)
		for(int j=0;j<m;++j)
			if(a[i][j]=='h')ans+=fd(i,j);
    printf("%lld\n",ans);
    return 0;
}

过了很久,我们队开了很多个题,一个都没写出来(赛后发现我们以为可做的是比较难的)
我的一个队友推出F题的答案是

\[\sum_{j=1}^{n}n^{\underline{j}}(2^{n-j}-1) \]

这个式子可以 \(O(n)\) 计算出 \(n\) 的答案,直接做会变成 \(O(nk)\) 的复杂度。
考虑线性递推。
已知

\[\sum_{j=1}^{n}n^{\underline{j}}(2^{n-j}-1) \]

\[\sum_{j=1}^{n+1}(n+1)^{\underline{j}}(2^{n-j+1}-1) \]

直接维护不好做,可以分开维护,维护

\[\sum_{j=1}^{n+1}(n+1)^{\underline{j}}2^{n-j+1}和-\sum_{j=1}^{n+1}(n+1)^{\underline{j}} \]

因为 \(\sum_{j=1}^{n+1}(n+1)^{\underline{j}}=(n+1)+(n+1)n+...+(n+1)!\)\(\sum_{j=1}^{n}n^{\underline{j}}=n+(n-1)n+...+(n)!\)
所以 \(\sum_{j=1}^{n+1}(n+1)^{\underline{j}}=\sum_{j=1}^{n}n^{\underline{j}}*(n+1)+(n+1)\)
同理可推。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e7 + 9, mod= 998244353;
int ans1[N],ans2[N],mi;
int t;
signed main()
{
	ans1[1]=ans2[1]=0;
	ans1[2]=2,ans2[2]=4;
	mi=4;
	for(int i=3;i<=1e7;i++)	
	{
		ans1[i]=(ans1[i-1]*i+i)%mod;
		ans2[i]=(ans2[i-1]*i+i*mi)%mod;	
		mi=mi*2%mod;
	}
	scanf("%d",&t);
	while(t--)
	{
		int x;
		scanf("%d",&x);
		printf("%lld\n",(ans2[x]-ans1[x]+mod)%mod);
	}
	return 0;
} 

既然说好了是劣弧,所以肯定只能在向左或者向右的 \(len>>1\) 个点中寻找(貌似不说也是这么干)。

再看如何寻找最小长度,线性一个个查找肯定不现实,所以就考虑区间最大值如何去操作。

可以发现有一个性质,一个区间内,一旦一个端点被固定下之后,这个区间内的最大值会随着区间的扩大而非严格单调递增,那么就找到这个区间的单调性了,现在多了一个二分可以选择。

维护区间最大值,看数据范围,可以用 ST 表进行维护。

现在就有了一种做法,确定一个位置,然后向前向后分别二分进行查找。

时间复杂度为 \(O(nlogn)\),可以通过此题。

#include <bits/stdc++.h>
using namespace std;
int n,a[300010],st[300010][32],lg[300010];
int query(int l,int r)
{
	int q=lg[r-l+1];
	return max(st[l][q],st[r-(1<<q)+1][q]);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		st[i][0]=st[i+n][0]=st[i+n+n][0]=a[i];
	}
	lg[0]=-1;
	for(int i=1;i<=n+n+n;i++)lg[i]=lg[i>>1]+1;
	for(int j=1;(1<<j)<=n+n+n;j++)
		for(int i=1;i+(1<<j)-1<=3*n;i++)
			st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
	for(int i=1;i<=n;i++)
	{
		int x,cur;
		scanf("%d",&x);
		int l=1,r=n,ii=i+n;
		while(l<r)
		{
			int mid=l+r>>1;
			if(max(query(ii-mid,ii-1),query(ii+1,ii+mid))>=x)r=mid;
			else l=mid+1;
		}
		if(l==n)printf("-1 "); 
		else printf("%d ",l);
	}
	return 0;
 } 

这次ACM第二简单的题没人写,一直死磕难的题,导致我们组得分偏低,正式比赛要吸取教训,但这次让我看到了同学们非常厉害的地方,每个人都有自己擅长的方面。没改完的题下次一定

posted @ 2024-07-30 20:19  storms11  阅读(8)  评论(0编辑  收藏  举报