1 条题解

  • 0
    @ 2025-8-24 22:00:14

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 阿丑
    ArrTue

    搬运于2025-08-24 22:00:14,当前版本为作者最后更新于2022-11-03 14:44:29,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    update:修改了一些 LaTeX 问题(\not\mid->\nmid),增加了 k 的数据范围。

    题目传送门

    前置知识:

    扩展欧几里得算法,容斥 / 子集反演。

    题意:

    • 给定 nn,表示有一个长为 nn 的未知数组 xx
    • 给定 mm 个数 kik_i,表示 t<xki,tN\forall t<\frac x{k_i},t\in\mathbb N,已知 i=tki+1min(n,(t+1)ki)xi\sum_{i=tk_i+1}^{\min(n,(t+1)k_i)}x_i
    • 问有多少 ii 满足 xix_i 被唯一确定。
    • 2ki<n1092\le k_i<n\le10^9m10m\le10

    分析:

    ss 表示 xx 的前缀和,即 si=j=1ixjs_i=\sum_{j=1}^ix_j

    则条件即为已知 sks0,s2ksk,,snstks_k-s_0,\,s_{2k}-s_k,\,\dots,\,s_n-s_{tk}。又已知 s0=0s_0=0,故条件转化为已知 sk,s2k,,sns_k,s_{2k},\dots,s_n,即已知若干个前缀和。所以,xix_i 被唯一确定,当且仅当 sis_isi1s_{i-1} 均已知。

    考虑哪些 ii 满足 sis_i 已知。由上述分析知 sis_i 已知当且仅当 kj,kji\exists k_j,k_j\mid ii=ni=n。为了方便,我们令 km+1=nk_{m+1}=n。这样,sis_i 被确定当且仅当 kj,kji\exists k_j,k_j\mid i

    考虑哪些 ii 满足 xix_i 被确定,即 si1s_{i-1}sis_i 均已知。xix_i 被确定当且仅当 kj1,kj1i\exists k_{j_1},k_{j_1}\mid ikj2,kj2i1\exists k_{j_2},k_{j_2}\mid i-1

    若只有一对 kj1,kj2k_{j_1},k_{j_2},则可以令 i=akj1=bkj2+1i=ak_{j_1}=bk_{j_2}+1,有 akj1bkj2=1ak_{j_1}-bk_{j_2}=1。由扩展欧几里得相关知识可以求解。

    然而,此时有很多对 kk,只需满足其中之一即可,故不能直接推出形如 i=aki=aki=bk+1i=bk+1 的性质;若对所有 kk 两两之间计算贡献,又会算重。注意到 mm 非常小,所以可以对于所有 kjk_j 枚举是否有 kjik_j\mid ikji1k_j\mid i-1,避免了算重。具体地,对于全集 U={1,2,,m+1}U=\{1,2,\dots,m+1\} 的子集 S,VS,V,记 f(S,V)f(S,V) 为满足 jSkjij\in S\Leftrightarrow k_j\mid ijVkji1j\in V\Leftrightarrow k_j\mid i-1ii 的数量,我们可以考虑算出 S,Vf(S,V)\sum_{S\ne\varnothing,V\ne\varnothing}f(S,V)

    然而,f(S,V)f(S,V) 并不好算,因为即使我们知道了所有 kjik_j\mid i 是否成立,也与我们能求的“只有一对 kj1,kj2k_{j_1},k_{j_2}”的情况相去甚远。但注意到如果忽略所有 kjik_j\nmid i 的限制,即只考虑 kjik_j\mid i,那么 ii 受到的限制即为 lcmjS{kj}i\text{lcm}_{j\in S}\{k_j\}\mid i。记 K=lcmjS{kj}K=\text{lcm}_{j\in S}\{k_j\},情况转化为只有单个 KiK\mid i 的情况,是可做的。故考虑容斥。

    具体地,记 h(S,V)h(S,V) 为满足 jSkjij\in S\Rightarrow k_j\mid ijVkji1j\in V\Rightarrow k_j\mid i-1ii 的数量(注意 \Rightarrow\Leftrightarrow 的区别)。为了辅助,再记 g(S,V)g(S,V) 为满足 jSkjij\in S\Leftrightarrow k_j\mid ijVkji1j\in V\Rightarrow k_j\mid i-1ii 的数量。有:

    $$\begin{aligned} g(S,V)=&\sum_{V_1\supseteq V}f(S,V_1)\\ \Rightarrow f(S,V)=&\sum_{V_1\supseteq V}(-1)^{|V|-|V_1|}g(S,V_1)\\ \Rightarrow \sum_{V\ne\varnothing}f(S,V)=&g(S,\varnothing)-f(S,\varnothing)\\ =&\sum_{V\ne\varnothing}(-1)^{|V|-1}g(S,V) \end{aligned} $$

    同理,

    $$\begin{aligned} h(S,V)=&\sum_{S_1\supseteq S}g(S_1,V)\\ \Rightarrow g(S,V)=&\sum_{S_1\supseteq S}(-1)^{|S|-|S_1|}h(S_1,V)\\ \Rightarrow \sum_{S\ne\varnothing}g(S,V)=&h(\varnothing,V)-g(\varnothing,V)\\ =&\sum_{S\ne\varnothing}(-1)^{|S|-1}h(S,V) \end{aligned} $$

    故:

    $$\begin{aligned} &\sum_{S\ne\varnothing}\sum_{V\ne\varnothing}f(S,V)\\ =&\sum_{S\ne\varnothing}\sum_{V\ne\varnothing}(-1)^{|V|-1}g(S,V)\\ =&\sum_{V\ne\varnothing}(-1)^{|V|-1}\sum_{S\ne\varnothing}g(S,V)\\ =&\sum_{V\ne\varnothing}(-1)^{|V|-1}\sum_{S\ne\varnothing}(-1)^{|S|-1}h(S,V)\\ =&\sum_{S\ne\varnothing,V\ne\varnothing}(-1)^{|S|+|V|}h(S,V) \end{aligned} $$

    可以枚举 S,VS,V,再用扩展欧几里得算法求出 h(S,V)h(S,V),复杂度 22mlogn2^{2m}\log n

    注意到存在 j0j_0 满足 j0Sj0Vj_0\in S\land j_0\in V 时,会推出 kj0ikj0i1k_{j_0}\mid i\land k_{j_0}\mid i-1,得 kj01k_{j_0}\mid 1,故一定无解,所以可以只枚举与 SS 不交的 VV,复杂度 3mlogn3^m\log n


    #include <bits/stdc++.h>
    #define rep(i, l, r) for(int i=l, _=r; i<=_; ++i)
    using namespace std;
    typedef long long ll;
    
    const int mM=11+2, mS=1<<11|9;
    ll exgcd(ll &a, ll &b, ll x, ll y) {
    	if(!y) return a=1, b=0, x;
    	ll res=exgcd(b, a, y, x%y);
    	b-=x/y*a;
    	return res;
    }
    
    int n, m, k[mM];
    int lcm[mS], cnt[mS];
    //lcm[s] 表示集合内所有 kj 的 lcm 
    
    int main() {
    
    	scanf("%d%d", &n, &m);
    	rep(i, 1, m) {
    		scanf("%d", k+i);
    	}
    	sort(k+1, k+m+1), m=unique(k+1, k+m+1)-k-1;
    	k[++m]=n;
    
    	rep(i, 1, m) {
    		lcm[1<<i-1]=k[i];
    	}
    	lcm[0]=1;
    	rep(s, 1, (1<<m)-1) {
    		cnt[s]=cnt[s>>1]+(s&1);
    		const int a=lcm[s&s-1], b=lcm[s&-s], g=__gcd(a, b);
    		if(a>n || b>n || (ll) a/g*b>n) lcm[s]=n+1;
    		//如果 lcm 过大,一定无解 
    		else lcm[s]=a/g*b;
    	}
    	int ans=0;
    	rep(s0, 1, (1<<m)-1) if(lcm[s0]<=n) {
    		const ll x=lcm[s0];	//i mod x = 0
    		for(int _1=_^s0, s1=_1; s1; s1=_1&s1-1) if(lcm[s1]<n) {
    			const ll y=lcm[s1];	//i mod y = 1
    			ll a, b, g=exgcd(a, b, x, y), l=x/g*y;
    			if(g>1) continue;
    			a=(a%y+y)%y;
    			assert(a*x%y==1);
    			ans+=(cnt[s0]+cnt[s1]&1? -1: 1)*(n/l+(n%l>=a*x));
    		}
    	}
    	printf("%d\n", ans);
    	return 0;
    }
    
    • 1

    信息

    ID
    3418
    时间
    500ms
    内存
    63MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者