ABC405
E - Fruit Lineup
问题陈述
你有 A 个苹果、 B 个桔子、 C 根香蕉和 D 粒葡萄。
要把这些 A+B+C+D 水果从左到右排成一行,使下面的条件全部成立,一共有多少种排列方法?对998244353取模
条件:
每个苹果都放在每根香蕉的左边。
每个苹果都放在每个葡萄的左边。
每个桔子都放在每个葡萄的左边。
在这里,苹果、橘子、香蕉和葡萄都是无法区分的。
赛时思路
无(想到组合数,但组合数写挂了,所以赛时一直在调组合数)
正解思路
发现题目的限制形式化的可以归结于以下三点
顺序要求:
ac
ad
bd
于是我们可以将整堆水果分成ab bc cd三堆(这里一堆内的水果可以随意排列)
枚举cd中c的数量c1,则cd中的排列方法cnt有C(c1+d-1,c1)种(c1+d-1是固定最后一个为葡萄,防止重复计数)
假设bc中b为b1个,ab中b为b2=b-b1个,已知c为c2=c-c1个,那么当前方案的贡献为:
cnt * C(b1+c2,b1) * C(a+b2,b2)
然而这里又要枚举b1从0到b
于是考虑范德蒙德卷积



于是原来的答案变为:
cnt*C(a+b+c2,b)
可直接求
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MOD=998244353;
int fac[3000005],infac[3000005];
int ksm(int a,int b,int p){
if(b==0) return 1;
if(b==1) return a%p;
int c=ksm(a,b/2,p);
c=c*c%p;
if(b%2==1) c=c*a%p;
return c%p;
}
int CC(int n,int m){
return fac[n]*infac[m]%MOD*infac[n-m]%MOD;
}
signed main()
{
int A,B,C,D;
cin>>A>>B>>C>>D;
int n=A+B+C+D;
fac[0]=1;
for(int i=1;i<=n;i++){
fac[i]=(fac[i-1]*i)%MOD;
}
infac[n]=ksm(fac[n],MOD-2,MOD);
for(int i=n-1;i>=1;i--){
infac[i]=(infac[i+1]*(i+1))%MOD;
}
infac[0]=1;
int ans=0;
for(int i=0;i<=C;i++){
int cnt=CC(D+i-1,i)%MOD*CC(A+B+C-i,B)%MOD;
ans+=cnt;
ans%=MOD;
}
cout<<ans<<'\n';
return 0;
}
F - Chord Crossing

呜呜自己太菜了,F一点没有思路/ll
正解思路:
先考虑什么时候可能会相交

所以问题转化成在平面直角坐标系上M次询问每次询问一个点(ci,di),问它是否在多少个矩形内
可以离线做二维数点
具体的,先进行二维差分(一般套路),把下界抹掉
问题进一步变为

对其一维进行排序
若相同需要保证加入在前,询问在后
需要树状数组(值域线段树)维护加入、询问有多少的值<=Bj(值域线段树上其实就是询问前缀和)
(三维数点:CDQ分治:按第一维排序,第二维CDQ分治,合并时归并排序,第三维插入树状数组)
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e6 + 5;
struct Node{
int x, y, id, d;// d: 对答案的贡献是1还是-1
bool operator < (const Node &t) const {
if(x != t.x) return x < t.x;
return id < t.id;
// 点的id都是 -1,让询问的id是正数
}
};
vector<Node> vec;
int ans[MAXN];
struct BIT{
#define lowbit(x) ((x)&(-(x)))
int tree[MAXN];
void add(int p,int d){
while(p < MAXN){
tree[p] += d;
p += lowbit(p);
}
}
int query(int p){
int res = 0;
while(p){
res += tree[p];
p -= lowbit(p);
}
return res;
}
}bit;
int n, m, q;
int main(){
scanf("%d%d",&n,&m);n *= 2;
for(int i = 1;i <= m;++i){
int c, d;
scanf("%d%d",&c,&d);
vec.push_back({c, d, -1, 1});
vec.push_back({d, c, -1, 1});
}
scanf("%d",&q);
for(int i = 1;i <= q;++i){
int a, b;
scanf("%d%d",&a,&b);
// [a,b] x [1,a]
vec.push_back({b, a, i, 1});
if(a-1) vec.push_back({a-1, a, i, -1});
// [a,b] x [b,n]
vec.push_back({b, n, i, 1});
if(a-1) vec.push_back({a-1, n, i, -1});
if(b-1) vec.push_back({b, b-1, i, -1});
if((a-1) && (b-1))vec.push_back({a-1, b-1, i, 1});
}
sort(vec.begin(), vec.end());
for(auto [x, y, id, d] : vec){
if(id == -1){
bit.add(y, d);
}
else{
ans[id] += d * bit.query(y);
}
}
for(int i = 1;i <= q;++i){
printf("%d\n",ans[i]);
}
return 0;
}
/*
4 2
2 4
6 8
1
3 7
*/

浙公网安备 33010602011771号