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题的答案是
这个式子可以 \(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第二简单的题没人写,一直死磕难的题,导致我们组得分偏低,正式比赛要吸取教训,但这次让我看到了同学们非常厉害的地方,每个人都有自己擅长的方面。没改完的题下次一定