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\)gabg 左边,og 左边。

考虑构造方式,先放好一段 a 和一段 g

\[\underbrace{aa\dots a}_{A\text{个}}\underbrace{gg\dots g}_{D\text{个}} \]

然后考虑把 b 插进去。枚举 ag 之间有几个 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;
}
posted @ 2025-05-10 23:13  Xuan_qwq  阅读(75)  评论(0)    收藏  举报