当前位置: 首页 > news >正文

郑州大学2024年寒假训练 Day7:数论

感觉这一块讲的有点太少了,只有辗转相除法,拓展欧几里得定理,素数筛,快速幂和逆元五个内容。数论的内容远远不止这些。不过一个视频也讲不了太多东西,讲的还是数学,也是没有办法。一边看题一边说吧。

辗转相除法:

辗转相除法又叫欧几里得算法,用来求解两个数的最大公因数(GCD,Greatest Common Divisor)。内容是 g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)。中国有一个类似的算法叫做更相减损术,内容是 g c d ( a , b ) = g c d ( a , a − b ) = g c d ( b , a − b ) gcd(a,b)=gcd(a,a-b)=gcd(b,a-b) gcd(a,b)=gcd(a,ab)=gcd(b,ab) 其实内容上和欧几里得算法是一个东西。

证明 g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a\%b) gcd(a,b)=gcd(b,a%b)
不妨假设 a > b a>b a>b。设 d = g c d ( a , b ) d=gcd(a,b) d=gcd(a,b) ,那么 a = k 1 ∗ d , b = k 2 ∗ d a=k_1*d,b=k_2*d a=k1d,b=k2d , 则有 a % b = a − m ∗ b = k 1 ∗ d − m ∗ k 2 ∗ d = ( k 1 − m ∗ k 2 ) ∗ d a\%b=a-m*b=k_1*d-m*k_2*d=(k_1-m*k_2)*d a%b=amb=k1dmk2d=(k1mk2)d,余数仍然是最大公因数 d d d 的倍数。
还有种证明方法是这样的: a = q ∗ b + r a=q*b+r a=qb+r,其中 0 ≤ r < b 0\le r\lt b 0r<b,那么 a % b = r a\%b=r a%b=r。因为 a , b a,b a,b 的最大公因数 d d d 可以整除 a , b a,b a,b,即 d ∣ a d|a da d ∣ b d|b db ,所以 d ∣ ( q ∗ b ) d|(q*b) d(qb),所以 d ∣ ( r = a − q ∗ b ) d|(r=a-q*b) d(r=aqb),也就是说明余数 r r r d d d 的倍数。

( a , b ) → ( b , a % b ) (a,b)\rightarrow(b,a\%b) (a,b)(b,a%b) 是不断减小的,因此这样算下去的话,最终就会得到 a % b = 0 a\%b=0 a%b=0,此时的 a a a 就是最大公因数。这个辗转相除的过程最多不会超过 l o g log log 次,因此求解 g c d gcd gcd 的时间复杂度是 O ( l o g n ) O(logn) O(logn)

代码片段如下:
这里不需要判断ab谁大谁小并交换,因为再调用一次 gcd(b,a%b) 就实现了交换。

int gcd(int a,int b){return (b)?gcd(b,a%b):a;
}

更神秘的写法:
其实就是每次先对a模上b,然后交换ab,b^=a^=b^=实现的其实就是交换功能。

int gcd(int,a,int b){while(b)b^=a^=b^=a%=b;return a;
}

拓展欧几里得定理:

也就是exgcd(Extended gcd)。它主要是用来求解一次线性同余方程。也就是形如 a ∗ x ≡ c ( m o d p ) a*x\equiv c\pmod p axc(modp) x x x 的通解问题。这一篇讲的比较好

对这种问题,我们可以稍加转化,得到 a ∗ x + p ∗ y = c a*x+p*y=c ax+py=c 的等式,换种写法就是 a ∗ x + b ∗ y = c a*x+b*y=c ax+by=c,变成了二元一次方程求通解问题。在解决这个问题之前,我们可以算出 a ∗ x + b ∗ y = g c d ( a , b ) a*x+b*y=gcd(a,b) ax+by=gcd(a,b) 问题的通解,然后通过这个算式可以得到我们所求算式的通解。那么怎么求 a ∗ x + b ∗ y = g c d ( a , b ) a*x+b*y=gcd(a,b) ax+by=gcd(a,b) 的通解呢。

贝祖定理( B e ˊ z o u t B\'ezout Beˊzout 定理)

内容是 :对任意整数 a , b a,b a,b,存在一对整数 x , y x,y x,y,满足方程 a ∗ x + b ∗ y = g c d ( a , b ) a*x+b*y=gcd(a,b) ax+by=gcd(a,b)

证明使用归纳法。当 b = 0 b=0 b=0 时, x = 1 , y = 0 x=1,y=0 x=1,y=0 显然是方程的一组解( g c d ( a , 0 ) = a gcd(a,0)=a gcd(a,0)=a)。

b > 0 b>0 b>0,设我们知道方程 b ∗ x + ( a % b ) ∗ y = g c d ( b , a % b ) = g c d ( a , b ) b*x+(a\%b)*y=gcd(b,a\%b)=gcd(a,b) bx+(a%b)y=gcd(b,a%b)=gcd(a,b) 的解,求 a ∗ x + b ∗ y = g c d ( a , b ) a*x+b*y=gcd(a,b) ax+by=gcd(a,b) 的解。 b ∗ x + ( a % b ) ∗ y = g c d ( b , a % b ) b*x+(a\%b)*y=gcd(b,a\%b) bx+(a%b)y=gcd(b,a%b) b ∗ x + ( a − b ∗ ⌊ a b ⌋ ) ∗ y = g c d ( a , b ) b*x+(a-b*\left\lfloor\frac ab\right\rfloor)*y=gcd(a,b) bx+(abba)y=gcd(a,b) a ∗ y + b ∗ x − b ∗ ⌊ a b ⌋ ∗ y = g c d ( a , b ) a*y+b*x-b*\left\lfloor\frac ab\right\rfloor*y=gcd(a,b) ay+bxbbay=gcd(a,b) a ∗ y + b ∗ ( x − ⌊ a b ⌋ ∗ y ) = g c d ( a , b ) a*y+b*(x-\left\lfloor\frac ab\right\rfloor*y)=gcd(a,b) ay+b(xbay)=gcd(a,b)

b ∗ x + ( a % b ) ∗ y = g c d ( b , a % b ) b*x+(a\%b)*y=gcd(b,a\%b) bx+(a%b)y=gcd(b,a%b) 一组特解是 ( x 0 , y 0 ) (x_0,y_0) (x0,y0) ,可以发现, a ∗ x + b ∗ y = g c d ( a , b ) a*x+b*y=gcd(a,b) ax+by=gcd(a,b) 一组可行解就是 x = y 0 , y = x 0 − ⌊ a b ⌋ ∗ y 0 x=y_0,y=x_0-\left\lfloor\frac ab\right\rfloor*y_0 x=y0,y=x0bay0。我们用辗转相除法向下走到尽头,从最下面的 a ∗ 1 + b ∗ 0 = g c d ( a , 0 ) a*1+b*0=gcd(a,0) a1+b0=gcd(a,0) 一步一步向上推理,就可以得到原本式子的一组特解。

得到特解后会想得到 a ∗ x + b ∗ y = g c d ( a , b ) a*x+b*y=gcd(a,b) ax+by=gcd(a,b) 的通解,这个好说, a ∗ x a*x ax 多一个 a ∗ b g c d ( a , b ) \dfrac{a*b}{gcd(a,b)} gcd(a,b)ab,那么 b ∗ y b*y by 就少一个 a ∗ b g c d ( a , b ) \dfrac{a*b}{gcd(a,b)} gcd(a,b)ab 就行了。也就是说, x x x 每加一个 b g c d ( a , b ) \dfrac{b}{gcd(a,b)} gcd(a,b)b y y y 就减少一个 a g c d ( a , b ) \dfrac{a}{gcd(a,b)} gcd(a,b)a,可以维持等式不变。写成式子就是,通解 x ‾ = x + k ∗ b g c d ( a , b ) , y ‾ = y − k ∗ a g c d ( a , b ) \overline x=x+k*\dfrac{b}{gcd(a,b)},\overline y=y-k*\dfrac{a}{gcd(a,b)} x=x+kgcd(a,b)b,y=ykgcd(a,b)a。令 t 1 = b g c d ( a , b ) t1=\dfrac{b}{gcd(a,b)} t1=gcd(a,b)b,那么就是 x ‾ = x + k ∗ t 1 \overline x=x+k*t1 x=x+kt1,这相当于通解模 t 1 t1 t1 同余特解,即 x ‾ ≡ x ( m o d t 1 ) \overline x\equiv x\pmod{t1} xx(modt1),因此 x x x 的最小非负整数解就是 ( x % t 1 + t 1 ) % t 1 (x\%t1+t1)\%t1 (x%t1+t1)%t1,同理 y y y 的通解。

代码片段如下:

int exgcd(int a,int b,int &x,int &y){if(!b){x=1;y=0;return a;}int d=exgcd(b,a%b,x,y);int z=x;x=y;y=z-(a/b)*y;return d;
}

压行:

int exgcd(int a,int b,int &x,int &y){if(!b){x=1;y=0;return a;}int d=exgcd(b,a%b,y,x);//这里相当于交换了xy的值y-=a/b*x;return d;
}

另外提一嘴,对任意一个方程 a ∗ x + b ∗ y = d = g c d ( a , b ) a*x+b*y=d=gcd(a,b) ax+by=d=gcd(a,b) ,等式两边同时除以最大公因数 d d d,就得到了 a d ∗ x + b d ∗ y = 1 \dfrac ad*x+\dfrac bd*y=1 dax+dby=1 ,解和上面是一样的。也就是说当 a , b a,b a,b 互质时 a ∗ x + b ∗ y = 1 a*x+b*y=1 ax+by=1 一定有解。反之也成立(不然你 a , b a,b a,b 都是 d d d 的倍数, x , y x,y x,y 是整数,它们乘积的和也一定是 d d d 的倍数,但是 1 1 1 不包含任何大于1的因数,因此 a , b a,b a,b 不可能同时是任何一个 d d d 的倍数)。

拓展欧几里得值域分析:

因为在这里面无法取模,否则会导致出错,所以会担心运算过程中出现超大的数导致溢出。不过安心,所有x和y的中间值的绝对值都小于 ∣ m a x { a , b } ∣ |max\{a,b\}| max{a,b}。证明还是数学归纳法。详细的证明步骤在上面给出的博客中详细证明了。不多赘述。

裴蜀定理

内容:设 a , b a,b a,b 为正整数,则关于 a , b a,b a,b 的方程 a ∗ x + b ∗ y = c a*x+b*y=c ax+by=c 有整数解当且仅当 c c c g c d ( a , b ) gcd(a,b) gcd(a,b) 的倍数。

也就是说如果 c c c 不能被 g c d ( a , b ) gcd(a,b) gcd(a,b) 整除,方程无整数解,否则有整数解。不证明了。

我们通过上面的方式得到了 a ∗ x + b ∗ y = g c d ( a , b ) a*x+b*y=gcd(a,b) ax+by=gcd(a,b) 一组特解,现在要得到 a ∗ x + b ∗ y = c a*x+b*y=c ax+by=c 通解。先算特解,再找到通解的之间的变化量即可。这个好说,假设 c = k ∗ d c=k*d c=kd ,那么在等式 a ∗ x + b ∗ y = d = g c d ( a , b ) a*x+b*y=d=gcd(a,b) ax+by=d=gcd(a,b) 两边同时乘以 k = c d k=\dfrac cd k=dc 就完事了,式子就变成了 a ∗ ( c d ⋅ x ) + b ∗ ( c d ⋅ y ) = c a*(\dfrac cd\cdot x)+b*(\dfrac cd\cdot y)=c a(dcx)+b(dcy)=c。新的特解就是 x = c d ⋅ x , y = c d ⋅ y x=\dfrac cd\cdot x,y=\dfrac cd\cdot y x=dcx,y=dcy。不过由于系数没变,所以变化量是不变的,还是 t 1 = b d , t 2 = a d t1=\dfrac bd,t2=\dfrac ad t1=db,t2=da

总结,通过拓展欧几里得算法可以算出等式 a ∗ x + b ∗ y = d = g c d ( a , b ) a*x+b*y=d=gcd(a,b) ax+by=d=gcd(a,b) 一组特解 x 0 , y 0 x_0,y_0 x0,y0,那么等式 a ∗ x + b ∗ y = c a*x+b*y=c ax+by=c 一组特解是 x = c / d ∗ x 0 , y 0 = c / d ∗ y 0 x=c/d*x_0,y_0=c/d*y_0 x=c/dx0,y0=c/dy0,通解 x ‾ \overline x x 的变化量是 t 1 = b / d t1=b/d t1=b/d,通解 y ‾ \overline y y 的变化量是 t 2 = a / d t2=a/d t2=a/d。等式 a ∗ x + b ∗ y = c a*x+b*y=c ax+by=c 的通解为 x ‾ = x + k ∗ t 1 , y ‾ = y − k ∗ t 2 \overline x=x+k*t1,\overline y=y-k*t2 x=x+kt1,y=ykt2


素数筛

试除法(开方暴力)

我们想要知道一个数 x x x 是不是素数,朴素的想法是枚举 2 ∼ x − 1 2\sim x-1 2x1 ,暴力地尝试 x x x 能不能被其中一个整除。这样是 O ( n ) O(n) O(n) 的。一个显而易见的性质是,如果一个数 x x x 是合数,那么它一定存在一个质因数 p p p,而且 2 ≤ p ≤ x 2\le p \le \sqrt x 2px

反证法证明:假设合数 x x x 最小质因数为 p p p,如果上述性质不满足条件,说明 p > x p>\sqrt x p>x ,因为 x x x 为合数,因此 x x x 存在至少一个另一个质因数 q q q,根据题设 p p p 是最小的质因数,因此 q > = q q>=q q>=q,那么有 p ∗ q ≥ p 2 > ( x ) 2 = x p*q\ge p^2>(\sqrt x)^2=x pqp2>(x )2=x,两个因数的乘积大于了这个数,矛盾,因此 2 ≤ p ≤ x 2\le p \le \sqrt x 2px

所以我们枚举 2 ∼ ⌊ x ⌋ 2\sim \lfloor\sqrt x\rfloor 2x 就行了,时间复杂度是 O ( n ) O(\sqrt n) O(n )。代码如下:

bool isp(int x){if(x==1)return false;for(int i=2;i*i<=x;i++)if(x%i==0)return false;return true;
}

埃式筛

我们从 2 2 2 往后看每个数,如果这个数是质数,直接去标记一下它所有的倍数,这样就可以把有这个质因数的合数标记掉。如果一个数是合数,那么它一定存在小于它的质因子。如果我们对每个遇到的质因数都这样做,那么我们在看到一个合数之前,它一定会被标记掉。我们从前往后看到的所有没有标记的数都是素数。所以我们从 1 1 1 n n n 走一遍这种操作,就可以得到 1 ∼ n 1\sim n 1n 中所有的素数。

这种像筛子一样一次一次把合数筛出来的过程就是埃式筛,它筛数的次数约有: n / 2 + n / 3 + n / 5 + ⋯ + n / p + … ( p 是质数 ) ≤ n / 1 + n / 2 + n / 3 + ⋯ + n / n n/2+n/3+n/5+\dots+n/p+\dots\quad (p是质数)\le n/1+n/2+n/3+\dots+n/n n/2+n/3+n/5++n/p+(p是质数)n/1+n/2+n/3++n/n ,当 n → ∞ n\rightarrow\infty n 时, n / 1 + n / 2 + n / 3 + ⋯ + n / n = n l o g n n/1+n/2+n/3+\dots+n/n=nlogn n/1+n/2+n/3++n/n=nlogn(这东西学名叫调和级数,想看证明可以搜),因此埃式筛的筛的次数也就是时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),而且是常数很小的 n l o g n nlogn nlogn。代码如下:

bool vis[maxn];
void eratosthenes(int n){vis[1]=true;for(int i=2;i<=n;i++){if(!vis[i])for(int j=2*i;j<=n;j+=i)vis[j]=true;}
}

欧拉筛

上面发现一个合数可能会被筛去多次,有没有办法使得每个数只被筛去一次?有。

我们想要一个合数只被它最小的质因数与和它对应的次大的因数(最大因数就是它本身)筛去。当我们看到一个数的时候,枚举目前已经找到的质数,质数与我们看到的这个数相乘得到的数就是以枚举的质数为最小质因子的数。当我们枚举的质数已经可以整除我们现在看到的这个数的时候,就说明后面的质数不再小于等于我们看到的这个数的最小质因数了,就可以退出了。

通过这种想法,任何一个合数都一定会被它最小的质因数与和它对应的次大的因数筛去一次。所以时间复杂度是 O ( n ) O(n) O(n) 的。代码如下。

int prime[maxn],cnt;
bool vis[maxn];
void Eular(int n){for(int i=2;i<=n;i++){if(!vis[i])prime[++cnt]=i;for(int j=1,p=prime[1];j<=cnt && i*p<=n;p=prime[++j]){vis[i*p]=true;if(i%p==0)break;}}
}

这个筛的过程一定要融会贯通,因为它每个筛到的数都一定是这个数最小的质因数来筛,这个性质很强,所以对这个东西略微修改就可以同时处理很多有用的信息。比如每个数的最小质因数,每个数所有的质因数,计算欧拉函数,莫比乌斯函数等等。


快速幂

普通算 a b a^b ab 的方式就是把 b b b a a a 乘起来,时间复杂度是 O ( b ) O(b) O(b) 的。

发现一个东西,就是 a ∗ a = a 2 , a 2 ∗ a 2 = a 4 , a 4 ∗ a 4 = a 8 , . . . a*a=a^2,a^2*a^2=a^4,a^4*a^4=a^8,... aa=a2,a2a2=a4,a4a4=a8,... 通过这种方式可以快速算出指数很大的 a a a 的幂,然后我们再用预先算出来的这些幂指数去凑出答案的幂指数就行了。

举个例子,如果我们要算 a 10 a^{10} a10 ,那么我们可以先算出来 a 1 , a 2 , a 4 , a 8 a^1,a^2,a^4,a^8 a1,a2,a4,a8,然后 a 10 = a 2 ∗ a 8 a^{10}=a^2*a^8 a10=a2a8。当指数很大的时候,优势就更大了,比如 a 1025 = a 1024 ∗ a 1 a^{1025}=a^{1024}*a^1 a1025=a1024a1,而处理到 a 1024 a^{1024} a1024 只需要十次。

其实这东西有点像二进制,我们处理出来的是 a 1 ( 2 ) , a 1 0 ( 2 ) , a 10 0 ( 2 ) , a 100 0 ( 2 ) a^{1_{(2)}},a^{10_{(2)}},a^{100_{(2)}},a^{1000_{(2)}} a1(2),a10(2),a100(2),a1000(2) ,相乘其实就是幂指数相加,通过幂指数相加得到任何一个我们想要的幂指数。比如 a 10 = a 101 0 ( 2 ) = a 100 0 ( 2 ) + 1 0 ( 2 ) = a 100 0 ( 2 ) ∗ a 1 0 ( 2 ) a^{10}=a^{1010_{(2)}}=a^{1000_{(2)}+10_{(2)}}=a^{1000_{(2)}}*a^{10_{(2)}} a10=a1010(2)=a1000(2)+10(2)=a1000(2)a10(2)。想要凑出指数为 b b b,二进制位最多 l o g 2 b log_2b log2b 位,所以快速幂的时间复杂度为 O ( l o g 2 b ) O(log_2b) O(log2b)

代码如下:

ll qpow(ll a,ll b,ll mod){ll base=a%mod,ans=1;while(b){if(b&1){ans*=base;ans%=mod;}base*=base;base%=mod;b>>=1;}return ans;
}

逆元

这个东西主要是为了解决模意义下不能相除的问题。那么我们怎么才能实现相除呢?

假设 b b b 在取模意义下相当于 1 a \dfrac 1a a1 或者说 a − 1 a^{-1} a1,那么有 a ∗ b ≡ 1 ( m o d p ) a*b\equiv1\pmod p ab1(modp)

费马小定理:

内容:若 p p p 是质数,且 a a a 不是 p p p 的倍数,则有: a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1\pmod p ap11(modp)

它是欧拉定理的一个特例,不过在大部分情况下已经够用。这里要特别注意限定条件必须满足。因为 a p − 1 ≡ 1 ( m o d p ) a^{p-1}\equiv1\pmod p ap11(modp),所以 a p − 2 ∗ a ≡ 1 ( m o d p ) a^{p-2}*a\equiv1\pmod p ap2a1(modp),这里 a p − 2 a^{p-2} ap2 就实现了上面的 b b b 的功能,因此 a p − 2 ≡ 1 a ( m o d p ) a^{p-2}\equiv \dfrac 1a\pmod p ap2a1(modp)

简单来说,如果模数是质数 p p p,要除以 a a a,那么就直接乘以 a p − 2 a^{p-2} ap2 就可以实现相同的作用了。


A - 最大公约数和最小公倍数问题

思路:

如果把 x 0 , y 0 x_0,y_0 x0,y0 质因数分解,就得到了 x 0 = p 1 c 1 ∗ p 2 c 2 ∗ p 3 c 3 ∗ ⋯ ∗ p i c i , y 0 = p 1 t 1 ∗ p 2 t 2 ∗ p 3 t 3 ∗ ⋯ ∗ p j t j x_0=p_1^{c_1}*p_2^{c_2}*p_3^{c_3}*\dots*p_i^{c_i},y_0=p_1^{t_1}*p_2^{t_2}*p_3^{t_3}*\dots*p_j^{t_j} x0=p1c1p2c2p3c3pici,y0=p1t1p2t2p3t3pjtj,而且 t i ≥ c i t_i\ge c_i tici。对 P , Q P,Q P,Q 来说,它们肯定都有 x 0 x_0 x0 的质因数部分,而从 x 0 x_0 x0 y 0 y_0 y0 的这一块质因数部分完全不重合。也就是说从 y 0 x 0 = p 1 m 1 ∗ p 2 m 2 ∗ p 3 m 3 ∗ ⋯ ∗ p j m j \frac {y_0} {x_0}=p_1^{m_1}*p_2^{m_2}*p_3^{m_3}*\dots*p_j^{m_j} x0y0=p1m1p2m2p3m3pjmj ,取出若干种质因数 p k m k p_k^{m_k} pkmk 分给 P P P,剩下的分给 Q Q Q 就是一个可行的解。(每种质因数只能分给 P , Q P,Q P,Q 其中一个,否则分给 P , Q P,Q P,Q 的部分会出现重合)

因为一种质因数要么分给 P P P,要么分给 Q Q Q,每种质因数有两种选择,如果 y 0 x 0 \frac {y_0} {x_0} x0y0 x x x 种质因数,那么分法也就是答案就有 2 x 2^x 2x 种。

code:

#include <iostream>
#include <cstdio>
using namespace std;int x,y;int main(){cin>>x>>y;if(y%x){cout<<0;return 0;}x=y/x;int cnt=0;for(int i=2;i*i<=x;i++)if(x%i==0){cnt++;while(x%i==0)x/=i;}if(x>1)cnt++;cout<<(1ll<<cnt);return 0;
}

B - 二元一次不定方程 (exgcd)

思路:

求解形如 a ∗ x + b ∗ y = c a*x+b*y=c ax+by=c 方程的通解已经在上面详细描述过了,这里尝试算出正整数解的个数和 x , y x,y x,y 的最大和最小正整数解。

假设我们已经算到了 x ‾ = x + k ∗ t 1 , y ‾ = y − k ∗ t 2 \overline x=x+k*t1,\overline y=y-k*t2 x=x+kt1,y=ykt2 x , y x,y x,y 的最小正整数解好算,先看 x x x因为是正整数解,不是非负整数解,不包括0,解的值域应该是 [ 1 , t 1 ] [1,t1] [1,t1],所以我们的计算式应该是 x m i n = ( ( x − 1 ) % t 1 + t 1 ) % t 1 + 1 x_{min}=((x-1)\%t1+t1)\%t1+1 xmin=((x1)%t1+t1)%t1+1,同理 y m i n = ( ( y − 1 ) % t 2 + t 2 ) % t 2 + 1 y_{min}=((y-1)\%t2+t2)\%t2+1 ymin=((y1)%t2+t2)%t2+1

x x x 取到最大正整数解时, y y y 此时应该正好取到最小正整数解,因此我们把 y m i n y_{min} ymin 代入,算出此时的 x x x 即可。同理 y y y

正整数解的个数其实就看一个变量就可以了。比如看 x x x ,其实就是 x m i n x_{min} xmin x m a x x_{max} xmax 中间差了几个 t 1 t1 t1

code:

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;ll T,a,b,c;ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll d=exgcd(b,a%b,x,y);ll z=x;x=y;y=z-(a/b)*y;return d;
}int main(){cin>>T;while(T--){scanf("%lld%lld%lld",&a,&b,&c);ll x,y,d=exgcd(a,b,x,y);if(c%d){printf("-1\n");continue;}x=c/d*x;y=c/d*y;ll t1=b/d,t2=a/d;ll xmi=((x-1)%t1+t1)%t1+1,ymi=((y-1)%t2+t2)%t2+1,xmx,ymx;xmx=(c-ymi*b)/a;ymx=(c-xmi*a)/b;if(xmx<=0 || ymx<=0){printf("%lld %lld\n",xmi,ymi);}else {printf("%lld %lld %lld %lld %lld\n",(xmx-xmi)/t1+1,xmi,ymi,xmx,ymx);}}return 0;
}

C - 质因数分解

思路:

枚举所有可能的因数,得到的第一个因数对应的另一个因数就是答案。

根据上面提到的性质,如果一个数 x x x 是合数,那么它一定存在一个质因数 p p p,而且 2 ≤ p ≤ x 2\le p \le \sqrt x 2px 。我们最多找到 x \sqrt x x 就能找到答案了。

code:

#include <iostream>
#include <cstdio>
using namespace std;int n;int main(){cin>>n;for(int i=2;i*i<=n;i++)if(n%i==0){cout<<n/i;return 0;}return 0;
}

D - 质数筛

思路:

写作素数筛,读作开方暴力,直接暴力验证每个数是不是质数就行了。

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=105;int n,a[maxn];bool isp(int x){if(x==1)return false;for(int i=2;i*i<=x;i++)if(x%i==0)return false;return true;
}int main(){cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)if(isp(a[i]))cout<<a[i]<<" ";return 0;
}

E - Prime Distance

题意:

给你两个数 L , U L,U L,U 1 ≤ L < U ≤ 2147483647 1\le L< U\le 2147483647 1L<U2147483647 U − L ≤ 1000000 U-L\le 1000000 UL1000000 。问 L ∼ U L\sim U LU 中相邻的两个质数中差值最小和最大的一对质数是什么。

思路:

直接跑筛法是跑不动的,但是根据一个数 x x x 如果是合数,那么一定存在一个小于等于 x \sqrt x x 的质因数的性质可以知道, L ∼ U L\sim U LU 中的所有合数最大的最小质因数不会超过 U \sqrt U U ,我们直接预处理处理 U \sqrt U U 以内的所有素数,然后对每个素数筛掉 L ∼ U L\sim U LU 中它的倍数, L ∼ U L\sim U LU 中剩下的没有被筛掉的数就是素数。

需要注意当 L = 1 L=1 L=1 时,会有一个 1 1 1 不会被筛掉,而它既不是素数也不是合数,因此需要特判去除。

code:

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=1e5+5;
typedef long long ll;
const ll inf=1e18;ll L,U;int prime[maxn],cnt;
bool tvis[maxn*50];
void Eular(int n){tvis[1]=true;for(int i=2;cnt<=n;i++){if(!tvis[i])prime[++cnt]=i;for(int j=1,p=prime[1];j<=cnt && i*p<maxn*50;p=prime[++j]){tvis[i*p]=true;if(i%p==0)break;}}
}int main(){Eular(1e5);while(cin>>L>>U){vector<bool> vis(U-L+5);if(L==1)vis[0]=true;for(ll i=1,p=prime[1];i<=cnt && p*p<=U;p=prime[++i])for(ll j=max((L+p-1)/p,2ll);j*p<=U;j++)vis[j*p-L]=true;ll dmi=inf,dmx=0,l1,r1,l2,r2;for(ll i=0,lst=-1;i<=U-L;i++){if(!vis[i]){if(~lst){if(i-lst<dmi){dmi=i-lst;l1=lst;r1=i;}if(i-lst>dmx){dmx=i-lst;l2=lst;r2=i;}lst=i;}else lst=i;}}if(dmx)printf("%lld,%lld are closest, %lld,%lld are most distant.\n",L+l1,L+r1,L+l2,L+r2);else printf("There are no adjacent primes.\n");}return 0;
}

F - 线性筛素数

思路:

素数筛板子, p r i m e prime prime 数组中记录的就是从 1 ∼ n 1\sim n 1n 的所有素数, p r i m e [ k ] prime[k] prime[k] 就是第 k k k 大的素数。

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1e7+5;int n,q;int prime[maxn],cnt;
bool vis[maxn*10];
void Eular(int n){for(int i=2;i<=n;i++){if(!vis[i])prime[++cnt]=i;for(int j=1,p=prime[1];j<=cnt && i*p<=n;p=prime[++j]){vis[i*p]=true;if(i%p==0)break;}}
}int main(){cin>>n>>q;Eular(n);for(int i=1,k;i<=q;i++){cin>>k;cout<<prime[k]<<endl;}return 0;
}

G - 又是毕业季II

思路:

好题。洛谷 P1414 又是毕业季II看不懂可以去题解区翻题解看

取出 k k k 个数的最大公因数,我们算一遍 看 看 个人的最大公因数是 k ∗ l o g k*log klog 次数的,再枚举选择数…不用想了,复杂度爆炸。

那怎么得到 k k k 个人的最大公因数。如果我们知道前 k − 1 k-1 k1 个人的最大公因数,如果第 k k k 个人有因数是这个最大公因数,那么最大公因数不变,否则是更小的需要所有人都有的因数。

嗯?如果我们一开始就对每个数标记一下以它为因数的人有几个不就好了,假设记录数组叫 v i s vis vis。这样处理一下的话,如果我们找 k k k 个人的最大公因数,就直接在 1 ∼ i n f = 1 0 6 1\sim inf=10^6 1inf=106 中找最大的 i i i,满足 v i s [ i ] ≥ k vis[i]\ge k vis[i]k 即可。

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=1e4+5;
const int maxf=1e6+5;int n,vis[maxf];//是i的倍数的有多少个 int ans[maxn];int main(){cin>>n;for(int i=1,t;i<=n;i++){cin>>t;for(int p=1;p*p<=t;p++)if(t%p==0){vis[p]++;if(p*p!=t)vis[t/p]++;}}for(int i=1e6;i>=1;i--)if(!ans[vis[i]])ans[vis[i]]=i;for(int i=n,mx;i>=1;i--){mx=max(mx,ans[i]);ans[i]=mx;}for(int i=1;i<=n;i++)cout<<ans[i]<<endl;return 0;
}

H - 快速幂

思路:

快速幂板题

code:

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;ll a,b,p;ll qpow(ll a,ll b,ll mod){ll base=a%mod,ans=1;while(b){if(b&1){ans*=base;ans%=mod;}base*=base;base%=mod;b>>=1;}return ans;
}int main(){cin>>a>>b>>p;printf("%lld^%lld mod %lld=%lld\n",a,b,p,qpow(a,b,p));return 0;
}

I - Carmichael Numbers

题意:

Alvaro 认为,与传统海鲜饭相比,加密海鲜饭的主要优势在于,除了你自己,没人知道你吃的是什么。

一个合数如果能够通过费马素性检验 a n m o d n = a a^n\ mod\ n=a an mod n=a就认为他是个一个 C a r m i c h a e l n u m b e r Carmichael\ number Carmichael number

现在给你一个数,问你它是不是 C a r m i c h a e l n u m b e r Carmichael\ number Carmichael number

思路:

可以先把合数筛出来。如果给的是合数,再进行一下费马素性检验,如果都能通过就输出 C a r m i c h a e l n u m b e r Carmichael\ number Carmichael number

code:

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=65005;int n;int prime[maxn],cnt;
bool vis[maxn];
void Eular(int n){vis[1]=true;for(int i=2;i<=n;i++){if(!vis[i])prime[++cnt]=i;for(int j=1,p=prime[1];j<=cnt && i*p<=n;p=prime[++j]){vis[i*p]=true;if(i%p==0)break;}}
}ll qpow(ll a,ll b,ll mod){ll base=a%mod,ans=1;while(b){if(b&1){ans*=base;ans%=mod;}base*=base;base%=mod;b>>=1;}return ans;
}int main(){Eular(65000);while(cin>>n,n){if(!vis[n]){printf("%d is normal.\n",n);continue;}bool f=true;for(int i=2;i<n;i++){if(qpow(i,n,n)!=i){f=false;//不满足素性检验 break;}}if(f)printf("The number %d is a Carmichael number.\n",n);else printf("%d is normal.\n",n);}return 0;
}

J - 因子和

思路:

洛谷 P1593 因子和

首先需要知道一个数 a a a 的所有因数和是多少。把 a a a 质因数分解,得到 a = p 1 c 1 ∗ p 2 c 2 ∗ p 3 c 3 ∗ ⋯ ∗ p m c m a=p_1^{c_1}*p_2^{c_2}*p_3^{c_3}*\dots*p_m^{c_m} a=p1c1p2c2p3c3pmcm 那么它的所有因数的和就是 s u m = ( 1 + p 1 + p 1 2 + ⋯ + p 1 c 1 ) ⋅ ( 1 + p 2 + p 2 2 + ⋯ + p 2 c 2 ) ⋅ ⋯ ⋅ ( 1 + p m + p m 2 + ⋯ + p m c m ) sum=(1+p_1+p_1^2+\dots+p_1^{c_1})\cdot(1+p_2+p_2^2+\dots+p_2^{c_2})\cdot\\\dots\cdot (1+p_m+p_m^2+\dots+p_m^{c_m}) sum=(1+p1+p12++p1c1)(1+p2+p22++p2c2)(1+pm+pm2++pmcm)

这个式子可以这样理解:我们从第一个括号里随便取一项,和第二个括号里随便取一项,以此类推,一直取到最后一个括号,这样就可以得到一个因数。因数一共有 ∏ i = 1 m ( c i + 1 ) \prod_{i=1}^{m}(c_i+1) i=1m(ci+1) 项,也正好是这些选取方案,取法和因数一一对应。

那么 a b a^b ab 的因数和就是: s u m = ( 1 + p 1 + p 1 2 + ⋯ + p 1 c 1 + ⋯ + p 1 b ∗ c 1 ) ⋅ ( 1 + p 2 + p 2 2 + ⋯ + p 2 b ∗ c 2 ) ⋅ ⋯ ⋅ ( 1 + p m + p m 2 + ⋯ + p m b ∗ c m ) sum=(1+p_1+p_1^2+\dots+p_1^{c_1}+\dots+p_1^{b*c_1})\cdot(1+p_2+p_2^2+\dots+p_2^{b*c_2})\cdot\\\dots\cdot (1+p_m+p_m^2+\dots+p_m^{b*c_m}) sum=(1+p1+p12++p1c1++p1bc1)(1+p2+p22++p2bc2)(1+pm+pm2++pmbcm)

第一个括号内是一个等比数列,首项为1,公比为 p 1 p_1 p1。因此第一个括号内的内容的总和 = 1 ∗ ( 1 − p 1 b ∗ c 1 + 1 ) 1 − p 1 = p 1 b ∗ c 1 + 1 − 1 p 1 − 1 =\dfrac {1*(1-p_1^{b*c_1+1})}{1-p_1}=\dfrac {p_1^{b*c_1+1}-1}{p_1-1} =1p11(1p1bc1+1)=p11p1bc1+11。对 p 1 b ∗ c 1 + 1 p_1^{b*c_1+1} p1bc1+1 求快速幂,对 p 1 − 1 p_1-1 p11 算逆元就能快速求解了,对一个数,处理出它所有的质因数和对应个数,每个质因数用这个过程算出答案,结果累乘起来即可。

不过 p 1 − 1 p_1-1 p11 可以计算逆元的前提条件是 p 1 − 1 ≢ 0 ( m o d 9901 ) p_1-1\not\equiv0\pmod {9901} p110(mod9901),因此当 p 1 ≡ 1 ( m o d 9901 ) p_1\equiv1\pmod {9901} p11(mod9901) 时的情况单独处理,发现原式子中这个数就等于 b ∗ c 1 + 1 b*c_1+1 bc1+1

注意 a = 0 a=0 a=0 的情况需要特判。

code:

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
const ll mod=9901;
#define pii pair<int,int>ll a,b;
vector<pii> t;ll qpow(ll a,ll b){b%=mod-1;ll base=a%mod,ans=1;while(b){if(b&1){ans*=base;ans%=mod;}base*=base;base%=mod;b>>=1;}return ans;
}
ll inv(ll x){return qpow(x,mod-2);}int main(){cin>>a>>b;if(a==0){cout<<0<<endl;return 0;}for(int i=2,cnt;i*i<=a;i++){if(a%i==0){cnt=0;while(a%i==0){a/=i;cnt++;}t.push_back(pii(i,cnt));}}if(a>1)t.push_back(pii(a,1));ll ans=1;for(auto x:t){ll p=x.first,c=x.second;if(p%mod!=1)ans=ans*(qpow(p%mod,b*c+1)-1)%mod*inv(p-1)%mod;else ans=ans*(b*c+1)%mod;}cout<<(ans%mod+mod)%mod;return 0;
}

相关文章:

郑州大学2024年寒假训练 Day7:数论

感觉这一块讲的有点太少了&#xff0c;只有辗转相除法&#xff0c;拓展欧几里得定理&#xff0c;素数筛&#xff0c;快速幂和逆元五个内容。数论的内容远远不止这些。不过一个视频也讲不了太多东西&#xff0c;讲的还是数学&#xff0c;也是没有办法。一边看题一边说吧。 辗转…...

“目标检测”任务基础认识

“目标检测”任务基础认识 1.目标检测初识 目标检测任务关注的是图片中特定目标物体的位置。 目标检测最终目的&#xff1a;检测在一个窗口中是否有物体。 eg:以猫脸检测举例&#xff0c;当给出一张图片时&#xff0c;我们需要框出猫脸的位置并给出猫脸的大小&#xff0c;如…...

springboot+vue的宠物咖啡馆平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…...

LaWGPT—基于中文法律知识的大模型

文章目录 LaWGPT&#xff1a;基于中文法律知识的大语言模型数据构建模型及训练步骤两个阶段二次训练流程指令精调步骤计算资源 项目结构模型部署及推理 LawGPT_zh&#xff1a;中文法律大模型&#xff08;獬豸&#xff09;数据构建知识问答模型推理训练步骤 LaWGPT&#xff1a;基…...

一文弄明白KeyedProcessFunction函数

引言 KeyedProcessFunction是Flink用于处理KeyedStream的数据集合&#xff0c;它比ProcessFunction拥有更多特性&#xff0c;例如状态处理和定时器功能等。接下来就一起来了解下这个函数吧 正文 了解一个函数怎么用最权威的地方就是 官方文档 以及注解&#xff0c;KeyedProc…...

alibabacloud学习笔记06(小滴课堂)

讲Sentinel流量控制详细操作 基于并发线程进行限流配置实操 在浏览器打开快速刷新会报错 基于并发线程进行限流配置实操 讲解 微服务高可用利器Sentinel熔断降级规则 讲解服务调用常见的熔断状态和恢复 讲解服务调用熔断例子 我们写一个带异常的接口&#xff1a;...

Code Composer Studio (CCS) - Licensing Information

Code Composer Studio [CCS] - Licensing Information 1. Help -> Code Composer Studio Licensing Information2. Upgrade3. Specify a license fileReferences 1. Help -> Code Composer Studio Licensing Information 2. Upgrade ​​​ 3. Specify a license file …...

uniapp引入微信小程序直播组件

方法1.小程序跳转视频号直播 微信小程序跳转到视频号 1.1微信开放平台注册 https://open.weixin.qq.com/ 2.2 方法2.使用小程序提供的直播组件 参考 微信小程序跳转视频号直播 小程序直播官方文档 https://developers.weixin.qq.com/miniprogram/dev/component/live-play…...

五个简单的C#编程案例

案例一&#xff1a;Hello, World! csharp using System; class Program { static void Main() { Console.WriteLine("Hello, World!"); } } 这个案例是最基础的C#程序&#xff0c;它打印出“Hello, World!”到控制台。每个C#程…...

Zlibrary低调官宣2024年最新网址,国内可直接访问,免费下载海量电子书籍

最近过节&#xff0c;文章也没怎么写&#xff0c;明天要上班了&#xff0c;今天写篇文章做个预热。 春节期间&#xff0c;“知识大航海”群里&#xff0c;有位群友分享了一个Zlibrary的最新地址&#xff0c;感谢这位群友妹妹的热心分享&#xff0c;这个地址国内可以直接访问。 …...

Android 开机启动

一、添加权限 <uses-permission android:name"android.permission.RECEIVE_BOOT_COMPLETED"/> 二、写一个广播接收器 public class BootReceiver extends BroadcastReceiver {Overridepublic void onReceive(Context context, Intent intent) {if(Intent.ACT…...

二叉树相关算法需了解汇总-基础算法操作

文章目录 144.二叉树的前序遍历145.二叉树的后序遍历94.二叉树的中序遍历102.二叉树的层序遍历107.二叉树的层次遍历倒序199.二叉树的右视图637.二叉树的层平均值429.N叉树的层序遍历515.在每个树行中找最大值116.填充每个节点的下一个右侧节点指针104.二叉树的最大深度111.二叉…...

万字干货-京东零售数据资产能力升级与实践

开篇 京东自营和商家自运营模式&#xff0c;以及伴随的多种运营视角、多种组合计算、多种销售属性等数据维度&#xff0c;相较于行业同等量级&#xff0c;数据处理的难度与复杂度都显著增加。如何从海量的数据模型与数据指标中提升检索数据的效率&#xff0c;降低数据存算的成…...

探索前端框架的世界:一场前端之旅

在网络世界中&#xff0c;网页开发领域的一颗明星是前端框架。这些框架为开发者提供了丰富的工具和技术&#xff0c;帮助他们构建出漂亮、高效的网页应用。现在&#xff0c;让我们随着小明的故事一起来探索一下吧。 小明的梦想 小明是一位年轻有为的前端开发者&#xff0c;他…...

class complex

class complex from C_OOP_base1_houjie complex.h #ifndef __COMPLEX__ // 防卫式声明 guard; 名称自定义 #define __COMPLEX__// 0. forward declarations class complex;complex& __doapl (complex* ths, const complex& r);// 1. class declarations class compl…...

数据库系统概论整理与总结

数据库系统概论 第一章&#xff1a;绪论 四个基本概念 四个概念 数据&#xff1a;Data 数据库&#xff1a;DataBase 数据库管理系统:DBMS 数据库系统:DBS 打个比喻&#xff0c;比如说菜鸟物流&#xff1a; Data&#xff1a;快递 DB&#xff1a;物流厂库 DBMS&#xff1a;对…...

打通新势力NAS权限壁垒,绿联私有云安装Portainer,实现更强大的Docker功能

打通新势力NAS权限壁垒&#xff0c;绿联私有云安装Portainer&#xff0c;实现更强大的Docker功能 对于国产新势力NAS来说&#xff0c;因为安全问题并没有完全开放SSH权限&#xff0c;所以还不能和传统NAS那样直接通过Docker run命令来部署容器&#xff0c;同时&#xff0c;对于…...

前端基础自学整理|DOM树

DOM&#xff0c;文档对象模型&#xff08;Document Object Model&#xff09;&#xff0c;简单的说&#xff0c;DOM是一种理念&#xff0c;一种思想&#xff0c;一个与系统平台和编程语言无关的接口&#xff0c;一种方法, 使 Web开发人员可以访问HTML元素&#xff01;不是具体方…...

RedisDesktopManager无法远程连接到Linux虚拟机中Redis的docker容器的一种解决方案

1.问题描述 除了RedisDesktopManager以外&#xff0c;使用java代码也无法连接到centos7虚拟机中的docker容器中的Redis &#xff0c;按照网上其他博主的解决方案&#xff0c;在排除Linux防火墙问题&#xff0c;端口映射问题&#xff0c;redis.conf配置文件问题以后&#xff0c…...

HarmonyOS 权限 介绍

权限说明 权限等级 根据权限对于不同等级应用有不同的开放范围&#xff0c;权限类型对应分为以下三种&#xff0c;等级依次提高。 normal权限 normal 权限允许应用访问超出默认规则外的普通系统资源。 这些系统资源的开放&#xff08;包括数据和功能&#xff09;对用户隐私以及…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...