AT_abc405
这场比较水了。
A.Is it rated?
手速题,题面大白话照着干就行。
首杀 32s,遥不可及啊。
(嗯这个屑翻译先看一分钟)
#include<bits/stdc++.h>
using namespace std;
int r,x;
int main(){
cin>>r>>x;
if(x==1){
if(1600<=r&&r<=2999)cout<<"Yes";
else cout<<"No";
}
else if(1200<=r&&r<=2399)cout<<"Yes";
else cout<<"No";
}
B.Not All
\(N\le 100\) 随便写,找到第一个值域全覆盖的前缀输出 \(N-\) 长度,没有就是 \(0\)。
#include<bits/stdc++.h>
using namespace std;
int n,m,tot,cnt[105];
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int a;cin>>a;
if(!cnt[a])tot++;
cnt[a]++;
if(tot==m){
cout<<n-i+1<<endl;
return 0;
}
}
cout<<'0'<<endl;
return 0;
}
C.Sum of Product
\[\sum_{1\le i< j\le N}A_iA_j=\frac{(\sum_{i=1}^N A_i)^2-\sum_{i=1}^N A_i^2}{2}
\]
done.
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,cnt1,cnt2;
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
int a;cin>>a;
cnt1+=a;cnt2+=a*a;
}
cout<<(cnt1*cnt1-cnt2)/2<<endl;
return 0;
}
D.Escape Route
从每个出口开始广搜即可,遍历到一个格子的时候记录来的方向,注意不要弄反了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
const char P[4]={'^','v','<','>'};
char mp[1005][1005];
char ans[1005][1005];
int n,m,dis[1005][1005];
struct node{
int x,y;
};
queue<node>q;
signed main(){
cin>>n>>m;
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
cin>>mp[i][j];
ans[i][j]=mp[i][j];
if(mp[i][j]=='E')q.push({i,j}),dis[i][j]=0;
}
while(q.size()){
int x=q.front().x,y=q.front().y;
q.pop();
for(int i=0;i<4;i++){
int nx=x+dx[i],ny=y+dy[i];
if(nx<1||ny<1||nx>n||ny>m||mp[nx][ny]!='.')continue;
if(dis[nx][ny]>dis[x][y]+1){
dis[nx][ny]=dis[x][y]+1;
ans[nx][ny]=P[i];
q.push({nx,ny});
}
}
}
for(int i=1;i<=n;i++,cout<<endl)for(int j=1;j<=m;j++)cout<<ans[i][j];
return 0;
}
E.Fruit Lineup
组合题。\(A\) 个 a
,\(B\) 个 o
,\(C\) 个 b
,\(D\) 个 g
,a
在 b
和 g
左边,o
在 g
左边。
考虑构造方式,先放好一段 a
和一段 g
。
\[\underbrace{aa\dots a}_{A\text{个}}\underbrace{gg\dots g}_{D\text{个}}
\]
然后考虑把 b
插进去。枚举 a
和 g
之间有几个 b
,然后变成:
\[\underbrace{aa\dots a}_{A\text{个}}\underbrace{bb\dots b}_{i\text{个}(0\le i\le C)}g\underbrace{??\dots ?}_{D+C-i-1\text{个}}
\]
这样有 \(C_{D+C-i-1}^{D-1}\) 的贡献。
再在 g
前面插入 o
,可以直接算,贡献是 \(C_{A+i+B}^{B}\)。
所以最终等价于求:
\[\sum_{i=0}^C C_{D+C-i-1}^{D-1}C_{A+i+B}^{B}
\]
记得取模,没了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
int ksm(int a,int q){
int res=1;
while(q){
if(q&1)res=res*a%mod;
a=a*a%mod;
q>>=1;
}
return res;
}
int A,B,C,D,ans;
int fac[4000005],inv[4000005];
int CC(int n,int m){
if(n<m||m<0)return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
signed main(){
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(int i=2;i<=4000002;i++)fac[i]=fac[i-1]*i%mod;
inv[4000002]=ksm(fac[4000002],mod-2);
for(int i=4000001;i>=2;i--)inv[i]=inv[i+1]*(i+1)%mod;
cin>>A>>B>>C>>D;
for(int i=0;i<=C;i++){
int tt=CC(D+C-i-1,C-i);
ans=(ans+tt*CC(A+i+B,B)%mod)%mod;
}
cout<<ans<<endl;
return 0;
}
F.Chord Crossing
人话翻译一下题面,等价于转换一下下标之后,求一个区间里出现奇数次的元素种类数。看起来很可以莫队,于是顶着 T 飞的风险写了一发过了。
块长乱调的,为了防 T 加了离散化一类的操作。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int B=1000;
int n,m,idx[400005],c[400005],ans[200005];
int x,y,res,cnt[200005];
struct node{
int l,r,id;
bool operator < (const node & B) const {
if(idx[l]!=idx[B.l])return l<B.l;
if(idx[l]&1)return r<B.r;
return r>B.r;
}
}a[200005],seg[200005];
void add(int x){
if(!c[x])return;
if(cnt[c[x]]==1)res--;
else if(cnt[c[x]]==0)res++;
cnt[c[x]]++;
}
void del(int x){
if(!c[x])return;
if(cnt[c[x]]==1)res--;
else if(cnt[c[x]]==2)res++;
cnt[c[x]]--;
}
int tt[400005],pps;
signed main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>x>>y;x/=2;y/=2;
seg[i]={x,y,i};
tt[++pps]=x;tt[++pps]=y;
}
sort(tt+1,tt+pps+1);
for(int i=1;i<=m;i++){
x=lower_bound(tt+1,tt+pps+1,seg[i].l)-tt;
y=lower_bound(tt+1,tt+pps+1,seg[i].r)-tt;
c[x]=c[y]=i;
}
for(int i=1;i<=m*2;i++)idx[i]=(i-1)/B+1;
int q;cin>>q;
for(int i=1;i<=q;i++){
cin>>a[i].l>>a[i].r,a[i].id=i;
if(a[i].l>a[i].r)swap(a[i].l,a[i].r);
a[i].l=(a[i].l+1)/2;
a[i].r=(a[i].r-1)/2;
a[i].l=lower_bound(tt+1,tt+pps+1,a[i].l)-tt;
a[i].r=upper_bound(tt+1,tt+pps+1,a[i].r)-tt-1;
}
sort(a+1,a+q+1);
for(int i=1,l=1,r=0;i<=q;i++){
while(r<a[i].r)add(++r);
while(l>a[i].l)add(--l);
while(r>a[i].r)del(r--);
while(l<a[i].l)del(l++);
ans[a[i].id]=res;
}
for(int i=1;i<=q;i++)cout<<ans[i]<<'\n';
return 0;
}
G.Range Shuffle Query
首先有序列重排数量 \(=\frac{|A|!}{\prod_{x\in A}cnt[x]}\)。
所以我们要维护的:\(cnt\) 前缀和,\(cnt\) 各项阶乘逆元的前缀积(令 \(0!=1\))
看起来也很可以莫队。于是写了一发树状数组+莫队 \(O(N\sqrt{N}\log N)\),不出意料地没过。
莫队是不变的了,考虑干掉 \(\log\),所以我们需要一个 \(O(1)\) 修改的东西。
容易想到对值域分块,\(O(1)\) 修 \(O(\sqrt{N})\) 查,很平衡,然后就过了。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353,B=500;
int n,Q,a[250005],l,r,x;
struct node{
int l,r,x,id;
bool operator < (const node & b) const {
if(l/B!=b.l/B)return l<b.l;
if(l/B&1)return r>b.r;
return r<b.r;
}
}q[250005];
int fac[250005],ifac[250005],inv[250005],ans[250005];
int c[250005],g[250005],f[250005];
void add(int x){
c[x]++;g[x/B]++;
f[x/B]=f[x/B]*inv[c[x]]%mod;
}
void del(int x){
f[x/B]=f[x/B]*c[x]%mod;
g[x/B]--;c[x]--;
}
int qry(int x){
int y=0,z=1;
for(int i=0;i<x/B;i++)y+=g[i],z=z*f[i]%mod;
for(int i=x/B*B;i<x;i++)y+=c[i],z=z*ifac[c[i]]%mod;
return fac[y]*z%mod;
}
signed main(){
cin>>n>>Q;
fac[0]=ifac[0]=inv[0]=inv[1]=1;
for(int i=0;i<=n/B;i++)f[i]=1;
for(int i=1;i<=n;i++){
cin>>a[i];fac[i]=fac[i-1]*i%mod;
if(i>1)inv[i]=mod-mod/i*inv[mod%i]%mod;
ifac[i]=ifac[i-1]*inv[i]%mod;
}
for(int i=1;i<=Q;i++){
cin>>l>>r>>x;
q[i]={l,r,x,i};
}
sort(q+1,q+Q+1);
for(int i=1,l=1,r=0;i<=Q;i++){
while(l>q[i].l)add(a[--l]);
while(r<q[i].r)add(a[++r]);
while(l<q[i].l)del(a[l++]);
while(r>q[i].r)del(a[r--]);
ans[q[i].id]=qry(q[i].x);
}
for(int i=1;i<=Q;i++)cout<<ans[i]<<'\n';
return 0;
}