7 .30 ACM總結

storms11發表於2024-07-30

放假前幾天,老師讓我們打一場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第二簡單的題沒人寫,一直死磕難的題,導致我們組得分偏低,正式比賽要吸取教訓,但這次讓我看到了同學們非常厲害的地方,每個人都有自己擅長的方面。沒改完的題下次一定