loj3304.「联合省选 2020 A」作业题
怎么会有二合一题目放在压轴题
前半部分直接欧拉反演,没啥营养:
然后显然是要 定理,但是普通的矩阵树都是求 ,而不能求 。
有一个经典 trick:我们把每条边变成一次多项式 ,然后按照正常的方式求行列式,得到的一次项系数就是答案。这是因为每个乘出一次的部分都相当于钦定了选一条边,其他边任意选的方案。
然后就没了。
#include<iostream>
#include<cstdio>
using namespace std;
#define int long long
const int mod=998244353;
inline int pw(int a,int b)
{
int res=1;
while(b)
{
if(b&1)
res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
struct edge
{
int x,y,w;
}e[1001];
struct cp
{
int x,y;
cp(int x_=0,int y_=0):
x(x_),y(y_){}
cp operator +(const cp &other) const
{
return cp((x+other.x)%mod,(y+other.y)%mod);
}
cp operator +=(const cp &other)
{
x=(x+other.x)%mod;
y=(y+other.y)%mod;
return *this;
}
cp operator -(const cp &other) const
{
return cp((x-other.x+mod)%mod,(y-other.y+mod)%mod);
}
cp operator -=(const cp &other)
{
x=(x-other.x+mod)%mod;
y=(y-other.y+mod)%mod;
return *this;
}
cp operator *(const cp &other) const
{
return cp((x*other.y%mod+y*other.x%mod)%mod,y*other.y%mod);
}
cp operator *=(const cp &other)
{
x=(x*other.y%mod+y*other.x%mod)%mod;
y=y*other.y%mod;
return *this;
}
cp operator /(const cp &other) const
{
return cp((x*other.y%mod-y*other.x%mod+mod)%mod*pw(other.y*other.y%mod,mod-2)%mod,y*pw(other.y,mod-2)%mod);
}
}g[31][31];
int maxn,ans,n,m,phi[200001],cnt,p[200001],sum[200001];
bool prime[200001];
inline int read()
{
int x=0;
char c=getchar();
while(c<'0'||c>'9')
c=getchar();
while(c>='0'&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x;
}
inline void init()
{
phi[1]=1;
for(register int i=2;i<=maxn;++i)
{
if(!prime[i])
{
p[++cnt]=i;
phi[i]=i-1;
}
for(register int j=1;j<=cnt&&i*p[j]<=maxn;++j)
{
prime[i*p[j]]=1;
if(i%p[j]==0)
{
phi[i*p[j]]=p[j]*phi[i];
break;
}
else
phi[i*p[j]]=(p[j]-1)*phi[i];
}
}
}
inline int solve()
{
cp ans=cp(0,1);
bool tag=0;
for(register int i=2;i<=n;++i)
{
for(register int j=i+1;j<=n;++j)
if(!g[i][i].y&&g[j][i].y)
{
swap(g[i],g[j]);
tag^=1;
break;
}
ans*=g[i][i];
cp d=cp(0,1)/g[i][i];
for(register int j=i;j<=n;++j)
g[i][j]*=d;
for(register int j=i+1;j<=n;++j)
{
d=g[j][i];
for(register int k=i;k<=n;++k)
g[j][k]-=g[i][k]*d;
}
}
return tag? (mod-ans.x)%mod:ans.x;
}
signed main()
{
n=read(),m=read();
for(register int i=1;i<=m;++i)
{
e[i].x=read(),e[i].y=read(),maxn=max(e[i].w=read(),maxn);
for(register int j=1;j*j<=e[i].w;++j)
if(e[i].w%j==0)
{
++sum[j];
if(j*j!=e[i].w)
++sum[e[i].w/j];
}
}
init();
for(register int d=1;d<=maxn;++d)
{
if(sum[d]<n-1)
continue;
for(register int i=1;i<=n;++i)
for(register int j=1;j<=n;++j)
g[i][j]=cp(0,0);
for(register int i=1;i<=m;++i)
{
if(e[i].w%d)
continue;
g[e[i].x][e[i].x]+=cp(e[i].w,1);
g[e[i].y][e[i].y]+=cp(e[i].w,1);
g[e[i].x][e[i].y]-=cp(e[i].w,1);
g[e[i].y][e[i].x]-=cp(e[i].w,1);
}
ans=(ans+phi[d]*solve()%mod)%mod;
}
printf("%lld\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?