2026.8.17
A
P2155 [SDOI2008] 沙拉公主的困惑 https://www.luogu.com.cn/problem/P2155
首先因为 \(\gcd(x,y)=\gcd(x+ky,y)\),发现有周期性,\(\forall k \in [1,\frac{n!}{m!}],[(k-1)m!+1,km!]\) 的质数都是相等的。所以答案为 \(\dfrac{n!}{m!}\varphi(m!)\)
需要用到的公式(其中 \(p\) 均为质数)
\[\varphi\left(x\right)=x\cdot\prod_{p\left|x\right.}^{}\left(1-\frac{1}{p}\right)=x\cdot\prod_{p\left|x\right.}^{}\left(\frac{p-1}{p}\right)
\]
然后发现 \(p|m!\) 和 \(p \le m\) 是等价的,因为:
- \(p \le m\),显然这个连乘因子一定会包含 \(p\);
- \(p > m\),\(m!\) 肯定不会包含 \(>m\) 的质因子。
\[\begin{aligned}
\text{ans} &= \frac{n!}{m!}\cdot \varphi(m!) \\
&= \frac{n!}{m!}\cdot m!\prod_{\substack{p\,\mid\,m!}} \frac{p-1}{p} \\
&= n!\cdot \frac{\displaystyle\prod_{\substack{p\in\mathbb{P}\\ p\le m}} (p-1)}{\displaystyle\prod_{\substack{p\in\mathbb{P}\\ p\le m}} p}
\end{aligned}
\]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
constexpr int N=1e7+3;
ll n,m,mod,fac[N]; //fac[i]:<=p[i]的所有质数的乘积
vector<int> p; bitset<N> vis;
ll fac1[N],fac2[N]; //n!,分子
void sieve(int V)
{
vis[1]=1;
for(int i=2;i<=V;i++)
{
if(!vis[i]) p.push_back(i);
for(int j:p)
{
if(i*j>V) break;
vis[i*j]=1;
if(i%j==0) break;
}
}
}
ll specialjudge()
{
cin>>n>>m;
if(m>=3) return 0;
else //m=1或2,n>=m
{
if(m==2)
{
if(n==2||m==3) return 1;
else return 0;
}
else
{
if(n==1) return 1;
else return 0;
}
}
}
ll ksm(ll a,ll b)
{
ll s=1;
while(b)
{
if(b&1) s=s*a%mod;
a=a*a%mod;
b>>=1;
}
return s;
}
ll solve()
{
cin>>n>>m;
if(m==1) return fac1[n];
if(n>=2*mod) return 0; //n!有2个mod,分母有0/1个mod,约不到
if(n>=mod&&m<mod) return 0; //n!有1个mod,分母有0个mod
int id=upper_bound(p.begin(),p.end(),m)-p.begin()-1;
// cerr<<p[id]<<' '<<fac1[n]<<' '<<fac2[id]<<' '<<fac[id]<<'\n';
return fac1[n]*fac2[id]%mod*ksm(fac[id],mod-2)%mod;
}
int main()
{
// freopen("neuvillette.in","r",stdin);
// freopen("neuvillette.out","w",stdout);
cin.tie(0)->sync_with_stdio(0);
int T;
cin>>T>>mod;
if(mod==2) while(T--) cout<<specialjudge()<<'\n';
fac1[0]=1;
for(int i=1;i<=1e7+3;i++)
{
if(i==mod) fac1[i]=fac1[i-1];
else fac1[i]=(fac1[i-1]*i)%mod;
}
// for(int i=1;i<=10;i++) cerr<<fac1[i]<<" \n"[i==10];
sieve(1e7+3);
fac[0]=2; fac2[0]=1;
for(int i=1;i<(int)p.size();i++)
{
if(p[i]==mod) fac[i]=fac[i-1];
else fac[i]=(fac[i-1]*p[i])%mod;
fac2[i]=(fac2[i-1]*(p[i]-1))%mod;
}
while(T--) cout<<solve()<<'\n';
cout.flush();
return 0;
}
/*
$$ n!\cdot\frac{\prod_{p\le m}^{}\left(p-1\right)}{\prod_{p\le m}^{}\left(p\right)} $$
注意n!和分母能不能约分一个mod
然后初始化阶乘遇到mod直接扔掉就好了
分母不用取模的,因为mod是质数,然后分母都是p-1?需要特判mod=2?
*/
D
P1800 [ICPC 2005 Tehran R] Software https://www.luogu.com.cn/problem/P1800
首先发现直接算出 \(t\) 非常困难。所以可以先固定 \(t\) 分析一下。
\(dp(i,x)\) 表示前 \(i\) 个人做 \(x\) 个零件 1,剩下时间全部去做零件2,能做出零件 2 的最大个数。
考虑前 \(i-1\) 个人做了 \(j-k\) 个模块 1,第 \(i\) 个人做了 \(k\) 个模块 1。
\[dp\left(i,x\right)=\max_{k=0}^{x}\left\lbrace dp\left(i-1,x-k\right)+\left\lfloor\frac{t-k\cdot d1_{i}}{d2_{i}}\right\rfloor\right\rbrace
\]
显然时间越短越难完成,所以答案具有单调性,直接二分 \(t\) 即可。

浙公网安备 33010602011771号