放假前幾天,老師讓我們打一場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題的答案是
這個式子可以 \(O(n)\) 計算出 \(n\) 的答案,直接做會變成 \(O(nk)\) 的複雜度。
考慮線性遞推。
已知
求
直接維護不好做,可以分開維護,維護
因為 \(\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第二簡單的題沒人寫,一直死磕難的題,導致我們組得分偏低,正式比賽要吸取教訓,但這次讓我看到了同學們非常厲害的地方,每個人都有自己擅長的方面。沒改完的題下次一定