【比赛链接】http://59.61.75.5:8018/contest/215
A. 格
【题意】
有一个 $n$ 行 $m$ 列的矩阵,初始所有位置的权值都为 $0$.
开始时,你在格子 $(x,y)$ 上。
每天早上,每个格子里的权值都会增加 $1$.
每天下午,你可以留在当前格子,或瞬移到上下左右相邻格子中的一个。
每天晚上,你会获得当前格子里的权值,然后清空当前格。
求第 $k$ 天晚上后,你所获权值的最大值。
多组询问。
【数据范围】$Tle 10^5,\, 1le n,mle 10^9,\,1le xle n,\,1le yle m,\,1le kle 10^{18}$。
【题解】
考虑 $n,m geq 2$ 的情况。当且仅当 $n,m$ 均为奇数且 $x,y$ 奇偶性相同时无法刚好走完一遍所有格子。在第一天下午先瞬移到相邻一格即可。因此考虑在最后 $n imes m$ 的时间内走完所有格子即可。若 $k< n times m$ 则走 $k$ 格即为答案。
考虑 $n=1$ 的情况,$k$ 很大时先走到一端,最后 $m$ 步走完即可。$k$ 较小时先往一边走几步,再折返回去。$m=1$ 同理。
效率 $O(T)$。期望得分:100。
【代码】
1 #include<bits/stdc++.h> 2 inline long long read ( void ) 3 { 4 long long x=0;char ch; 5 while ( !isdigit(ch=getchar()) ) ; 6 for ( x=ch^48; isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48); 7 return x; 8 } 9 inline long long sum ( long long l,long long r ) { return (l+r)%998244353LL*((r-l+1)%998244353LL)%998244353LL*499122177LL%998244353LL; } 10 signed main() 11 { 12 for ( int T=read();T--; ) 13 { 14 long long n=read(),m=read(),x=read(),y=read(),k=read(); 15 if ( n>1 and m>1 ) printf("%lld ",sum(std::max(k-n*m,0LL)+1,k)); 16 else 17 { 18 if ( m==1 ) std::swap(n,m),std::swap(x,y); 19 y=std::min(y,m-y+1); 20 if ( m-y+1>=k ) printf("%lld ",sum(1,k)); 21 else if ( k>=2*m-y-1 ) printf("%lld ",sum(k-m+1,k)); 22 else printf("%lld ",sum((k+y-m+1)/2,k)); 23 } 24 } 25 return 0; 26 }
C. 序列
【题意】
已知大小为 $n$ 的一个排列。
给定一个数 $k$,对这个排列的一个长度大于等于 $2$ 的子序列 $s=(s_1 ,dots,s_p)$,对于所有 $i<p$,若 $s_i<k<s_{i+1}$ 或 $s_i>k>s_{i+1}$,则得分加 $1$.
例如,当 $k=2$ 时,子序列 $5134$ 的得分为 $2$.
对 $kin [1,n]$,求所有给定排列的子序列的得分和.
【数据范围】$nle 10^5$。
【题解】
考虑一对元素 $i,j$ 的贡献。显然对所有 $k(a_i < k < a_j)$ 造成 $2^{i-1} imes 2^{n-j}$ 的贡献(反向同理)。
考虑每个 $j$ 造成的贡献。显然会由多个 $i$ 造成。
仔细分析,发现相当于两种操作:
① 对于 $k in [a_j+1,n]$,$w_k += 2^{i-1}$
② 对于 $k in [1,a_j-1]$,$ans_k+=w_k imes 2^{n-j}$
直接用分治或线段树维护即可。
效率 $O(n log n)$。注意内存限制。期望得分:100。
【代码】
1 #include<bits/stdc++.h> 2 inline int read ( void ) 3 { 4 int x=0;char ch; 5 while ( !isdigit(ch=getchar()) ) ; 6 for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48); 7 return x; 8 } 9 const int mod=1000000007; 10 const int maxn=100000+10; 11 int n,Pow[maxn],Ans[maxn],a[maxn],ans[maxn],val[maxn],add[maxn],del[maxn]; 12 std::pair<int,int> Q1[maxn],Q2[maxn]; 13 inline void CDQ ( int l,int r ) 14 { 15 if ( l==r ) return; 16 int mid=(l+r)>>1,cnt1=0,cnt2=0; 17 CDQ(l,mid);CDQ(mid+1,r); 18 for ( int i=l;i<=mid;i++ ) Q1[++cnt1]=std::make_pair(a[i],i); 19 for ( int i=mid+1;i<=r;i++ ) Q2[++cnt2]=std::make_pair(a[i],i); 20 std::sort(Q1+1,Q1+cnt1+1);std::reverse(Q1+1,Q1+cnt1+1); 21 std::sort(Q2+1,Q2+cnt2+1);std::reverse(Q2+1,Q2+cnt2+1); 22 for ( int i=1;i<=cnt1;i++ ) add[i]=(add[i-1]+Pow[Q1[i].second-1])%mod; 23 for ( int i=1;i<=cnt1+1;i++ ) del[i]=0; 24 for ( int i=1,j=0;i<=cnt2;i++ ) 25 { 26 while ( j<cnt1 and Q1[j+1].first>Q2[i].first ) j++; 27 ans[Q2[i].first+1]=(ans[Q2[i].first+1]+1LL*add[j]*Pow[n-Q2[i].second])%mod; 28 del[j]=(del[j]+mod-Pow[n-Q2[i].second])%mod; 29 } 30 for ( int i=cnt1;i;i-- ) del[i]=(del[i]+del[i+1])%mod; 31 for ( int i=1;i<=cnt1;i++ ) val[Q1[i].first]=(val[Q1[i].first]+del[i])%mod; 32 } 33 inline void solve ( void ) 34 { 35 for ( int i=1;i<=n;i++ ) val[i]=add[i]=del[i]=ans[i]=0; 36 CDQ(1,n); 37 for ( int i=1;i<=n;i++ ) ans[a[i]]=(ans[a[i]]+1LL*Pow[i-1]*val[a[i]])%mod; 38 for ( int i=1;i<=n;i++ ) ans[i]=(ans[i]+ans[i-1])%mod; 39 for ( int i=1;i<=n;i++ ) Ans[i]=(Ans[i]+ans[i])%mod; 40 } 41 signed main() 42 { 43 // freopen("sequence.in","r",stdin); 44 // freopen("sequence.out","w",stdout); 45 n=read();Pow[0]=1; 46 for ( int i=1;i<=n;i++ ) a[i]=read(),Pow[i]=2LL*Pow[i-1]%mod; 47 solve();std::reverse(a+1,a+n+1);solve(); 48 for ( int i=1;i<=n;i++ ) printf("%d ",Ans[i]); 49 return 0; 50 }