迷恋 题解
题目
题目描述
- 这不是正义的义务,而是作为正义的盟友!
- 不是盟友,而是正义本身,Onii-chan!
这一次,火姐妹 - 凯伦和Tsukihi - 正在前往他们从未到达的地方 - 水包围的岛屿!
有三种群岛,分别有三种颜色红色,蓝色和紫色的怪物。每种颜色的岛屿分别有a,b,c个。
桥梁在一些(可能全部或者部分)岛屿之间建成。桥梁双向连接两个不同的岛屿并具有长度1.对于任何两个相同颜色的岛屿,他们彼此不可达,或者它们之间的最短距离至少为3。这是为了防止同一种颜色的怪物种群相互蔓延。
火姐妹已经准备好了,但他们也想测试你的勇气。你在这里找出在限制下建立所有桥梁的不同方式的数量,并给出答案模数998244353(即答案要取余数)。只要有一对建桥的岛屿不一样,那么两种方法就是不一样的。
输入
第一行也仅包含三个空格分隔的整数a,b和c(1≤a,b,c≤5 000) - 红色,蓝色和紫色怪物的岛数。
输出
输出一行包含整数 - 构建桥接的不同方式的数量,模数为998244353。
样例输入1
1 1 1
样例输出1
8
样例输入2
1 2 2
样例输出2
63
样例输入3
1 3 5
样例输出3
3264
提示
注意
在第一个例子中,有3个桥可以建立,没有桥梁的设置违反了限制。所以答案是2^3 = 8。
在第二个例子中,下图中的上两个结构是有效的,下两个是无效的。
数据范围:
对于 的数据, 都小于等于5。
对于 的数据 小于等于5000
题目解析
我们发现有三种岛屿,但是我们可以先分析两种。不难发现,任意一个岛屿都不能连接与自己颜色相同的岛屿或者是两个同种颜色的岛屿。
然后发现如果有三种岛屿,这些条件还是成立的。
那么我们就可以设 为一种岛屿选 个,另一种岛屿选 个的情况。
答案就是 。
接下来考虑如何得到 。
step1
考虑DP方程式转移。
不难得出 ,显然这些情况下不能连一条边。
考虑 ,我们假设加入了一个第一种岛屿。
如果我们没有将这个岛屿连进去,那么总共有 种可能。
如果这个岛屿连进去了,那么一定有 种连法,但是同时连到的第二种岛屿就不能和其他岛屿连了,那么就是 种可能。
综上
代码
//O(N^2) #include<cstdio> #define maxn 5039 #define MOD 998244353 #define max(a,b) ((a)>(b)?(a):(b)) using namespace std; //#define debug typedef long long ll;//long long typedef int Type; inline Type read(){ Type sum=0; int flag=0; char c=getchar(); while((c<'0'||c>'9')&&c!='-') c=getchar(); if(c=='-') c=getchar(),flag=1; while('0'<=c&&c<='9'){ sum=(sum<<1)+(sum<<3)+(c^48); c=getchar(); } if(flag) return -sum; return sum; } ll f[maxn][maxn]; int a,b,c; int n; int main(){ //freopen("love.in","r",stdin); //freopen("love.out","w",stdout); a=read(); b=read(); c=read(); n=max(a,max(b,c)); for(int i=0;i<=n;i++) f[0][i]=f[i][0]=1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=((f[i-1][j-1]*j)%MOD+f[i-1][j])%MOD; #ifdef debug for(int i=0;i<=n;i++){ for(int j=0;j<=n;j++) printf("%6lld ",f[i][j]); putchar('\n'); } #endif printf("%lld",((f[a][b]*f[a][c])%MOD*f[b][c])%MOD); return 0; }
step2
step1的方法已经可以通过了,但是我们发现有些毒瘤出题人把 扩大到了 (两千万)
我们该怎么做呢?
显然我们还是设 为一种岛屿选 个,另一种岛屿选 个的情况,不妨设 。
我们发现在第一种岛屿和第二种岛屿都只能连一条边,我们可以枚举连边的数量。
然后我们固定第一种的方法不动,然后我们会发现对另一种进行排列就可以做到不重不漏了。
展开得
我们只需要预处理出 就可以 计算了。
由于要取模,所以还要预处理出 ,只需要阶乘逆元线性求即可,不会的可以点这里,(推销博客)
代码:
//O(N) #include<cstdio> #define MOD 998244353 #define maxn 5039 using namespace std; //#define debug typedef long long ll; typedef int Type; inline int max(int x,int y){ return x>y?x:y; } inline Type read(){ Type sum=0; int flag=0; char c=getchar(); while((c<'0'||c>'9')&&c!='-') c=getchar(); if(c=='-') c=getchar(),flag=1; while('0'<=c&&c<='9'){ sum=(sum<<1)+(sum<<3)+(c^48); c=getchar(); } if(flag) return -sum; return sum; } int a,b,c,n; ll inv[maxn],f[maxn]; ll pow(ll x,ll y){ ll res=1,tmp=x; while(y){ if(y&1) res=res*tmp%MOD; tmp=tmp*tmp%MOD; y>>=1; } return res; } void pre(){ f[0]=1; for(int i=1;i<=n;i++) f[i]=f[i-1]*i%MOD; inv[n]=pow(f[n],MOD-2); for(int i=n-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%MOD; return; } #define swap(x,y) x^=y^=x^=y; inline ll js(int i,int j){ ll res=0; if(i<j) swap(i,j);//i>=j for(int k=0;k<=j;k++) res=(res+f[i]*f[j]%MOD *inv[i-k]%MOD *inv[j-k]%MOD *inv[k]%MOD )%MOD; return res; } int main(){ freopen("love.in","r",stdin); freopen("love.out","w",stdout); scanf("%d%d%d",&a,&b,&c); n=max(a,max(b,c)); pre(); printf("%lld",js(a,b)*js(a,c)%MOD *js(b,c)%MOD ); return 0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析