[HAOI2011] 向量

首先将题目转化,转化为求方程:

\(k(a,b)+q(b,a)+w(a,−b)+c(b,−a)=(x,y)\)

将这个方程再次化简,即为:

\((k+w)a+(q+c)b=x\)

\((k-w)b+(q-c)a=y\)

到这里,我们可以联想到 \(Bézout\) 定理,\(Bézout\) 定理为 \(ax+by=c\) , \(x\) 和 \(y\) 有整数解的充要条件是 \(gcd(a,b)∣c\)

所以,为了使 \(k+w,q+c,k-w,q-c\) 都为整数的的充要条件是 \(a\) 和 \(b\) 的最大公因数都可以整除 \(x, y\),即为 \(gcd(a,b)∣x\) 且 \(gcd(a,b)∣y\)

考虑分类讨论:

1.当 \(k+w,q+c,k-w,q-c\) 都是偶数时:

在 \(gcd(a,b)∣x\) 且 \(gcd(a,b)∣y\) 的基础上可以再提取一波公因数 \(2\), 所以此时为 \(2gcd(a,b)∣x\) 且 \(2gcd(a,b)∣y\)

2.当 \(k+w,q+c,k-w,q-c\) 都是奇数时:

\((k+w)a+(q+c)b=x\) 两边同时加上 \(a+b\),可得 \((k+w+1)a+(q+c+1)b=x+a+b\)

此时 \(2gcd(a,b)∣x + a + b\) 且 \(2gcd(a,b)∣y +a + b\)

3.当 \(k+w,k-w\) 是偶数,\(q+c,q-c\) 都是奇数时:

\((k+w)a+(q+c)b=x\) 两边同时加上 \(b\),可得 \((k+w)a+(q+c+1)b=x+b\)

此时 \(2gcd(a,b)∣x + b\),同理, \(2gcd(a,b)∣y + a\)

4.当 \(k+w,k-w\) 是奇数,\(q+c,q-c\) 都是偶数时:

\((k+w)a+(q+c)b=x\) 两边同时加上 \(a\),可得 \((k+w+1)a+(q+c)b=x+a\)

此时 \(2gcd(a,b)∣x + a\),同理, \(2gcd(a,b)∣y + b\)

所以我们只需要 check 一下该组数据是否符合上面任一一种情况就可以了。

#include <iostream>
#include <cstdio>
#include <algorithm> #define rint register int
#define endl '\n'
#define int long long int k; bool f(int a, int b)
{
return (!(a % k)) and (!(b % k));
} signed main()
{
int T;
scanf("%lld", &T);
while (T--)
{
int a, b, x, y;
scanf("%lld%lld%lld%lld", &a, &b, &x, &y);
k = std::__gcd(a, b) * 2;
if (f(x, y) || f(x + a, y + b) || f(x + b, y + a) || f(x + a + b, y + a + b))
{
puts("Y");
}
else
{
puts("N");
}
}
return 0;
}

UVA12775 Gift Dilemma

求方程 \(Ax+By+Cz=P\space \space \space \space \space \space (x\ge0,y\ge0,z\ge0)\) 非负整数解的个数。

设\(d=\gcd(A,B,C)\)

\(d\times(\frac{A}{d}x+\frac{B}{d}y+\frac{C}{d}z)=P\)

显然,方程成立一定会有 \(d|P\)

则 \(\frac{A}{d}x+\frac{B}{d}y+\frac{C}{d}z=\frac{P}{d}\)

\(\frac{A}{d}x+\frac{B}{d}y=\frac{P}{d}-\frac{C}{d}z\)

设 \(c=\frac{P}{d}-\frac{C}{d}z\)

所以 \(\frac{A}{d}x+\frac{B}{d}y=c\)

可以扩展欧几里得定理求出 \(\frac{A}{d}x+\frac{B}{d}y=\gcd(\frac{A}{d},\frac{B}{d})\) 的一组整数特解 \(x_0,y_0\)

\(\frac{A}{d}x_0+\frac{B}{d}y_0=\gcd(\frac{A}{d},\frac{B}{d})\)

将两个式子同时除以 \(\gcd(\frac{A}{d},\frac{B}{d})\) 再乘 \(c\) ,可以得到:

\(\frac{A}{d}\times\frac{x_0c}{\gcd(\frac{A}{d},\frac{B}{d})}+\frac{B}{d}\times\frac{y_0c}{\gcd(\frac{A}{d},\frac{B}{d})}=c\)

得到原方程的整数特解

\(x_1=\frac{x_0c}{\gcd(\frac{A}{d},\frac{B}{d})},y_1=\frac{y_0c}{\gcd(\frac{A}{d},\frac{B}{d})}\)

因为 \(\frac{A}{d}\times x_1+\frac{B}{d}\times y_1=c\)

所以 \(\frac{A}{d}\times (x_1- \frac{B}{d\times\gcd(\frac{A}{d},\frac{B}{d})})+\frac{B}{d}\times (y_1+\frac{A}{d\times\gcd(\frac{A}{d},\frac{B}{d})})=c\)

这一步怎么来的呢?因为 \((- \frac{B}{d\times\gcd(\frac{A}{d},\frac{B}{d})} \times \frac{A}{d}) + (\frac{A}{d\times\gcd(\frac{A}{d},\frac{B}{d})} \times \frac{B}{d}) = 0\)

给定 \(x_1,y_1\) 变化的倍数,就是得到了通解的形式,其中 \(s\) 为任意整数。

\(\frac{A}{d}\times (x_1- s\times\frac{B}{d\times\gcd(\frac{A}{d},\frac{B}{d})})+\frac{B}{d}\times (y_1+s\times\frac{A}{d\times\gcd(\frac{A}{d},\frac{B}{d})})=c\)

因为要求的是非负整数解,所以

\(x_1- s\times\frac{B}{d\times\gcd(\frac{A}{d},\frac{B}{d})}\ge0\)

\(y_1+s\times\frac{A}{d\times\gcd(\frac{A}{d},\frac{B}{d})}\ge0\)

我们接着进行转换:

\(x_1\ge s\times\frac{B}{d\times\gcd(\frac{A}{d},\frac{B}{d})}\)

\(y_1\ge -s\times\frac{A}{d\times\gcd(\frac{A}{d},\frac{B}{d})}\)

即为

\(x_1\times\frac{d\times\gcd(\frac{A}{d},\frac{B}{d})}{B}\ge s\)

\(-y_1\times\frac{d\times\gcd(\frac{A}{d},\frac{B}{d})}{A}\le s\)

所以

\(-y_1\times\frac{d\times\gcd(\frac{A}{d},\frac{B}{d})}{A}\le s\le x_1\times\frac{d\times\gcd(\frac{A}{d},\frac{B}{d})}{B}\)

原方程的非负整数解个数即为:\(\lfloor x_1\times\frac{d\times\gcd(\frac{A}{d},\frac{B}{d})}{B}\rfloor-\lceil-y_1\times\frac{d\times\gcd(\frac{A}{d},\frac{B}{d})}{A}\rceil+1\)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath> #define rint register int
#define endl '\n'
#define int long long 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 - y * (a / b);
return d;
} signed main()
{
int T;
scanf("%lld", &T);
int idx = 0; while (T--)
{
idx++;
int A, B, C, P;
scanf("%lld%lld%lld%lld", &A, &B, &C, &P);
int x, y;
int ans = 0;
int d = exgcd(exgcd(A, B, x, y), C, x, y); if (P % d)
{
printf("Case %lld: 0\n", idx);
continue;
} int w = exgcd(A / d, B / d, x, y); int x0, y0;
int x1, y1;
x0 = x;
y0 = y; rint z = 0;
while (1)
{
if (P - z * C < 0)
{
break;
}
int c = P / d - C / d * z;
if (c % w)
{
z++;
continue;
}
x1 = x0 * c / w;
y1 = y0 * c / w;
ans += floor(x1 * d * 1.0 * w * 1.0 / B) - ceil(-y1 * d * 1.0 * w * 1.0 / A) + 1;
z++;
}
printf("Case %lld: %lld\n", idx, ans);
}
}

[SDOI2010] 古代猪文

题面很长,化简一下就是求 \(G^{\sum_{d|n}{C^{d}_{n}}}mod\ 999911659\)

我们发现 \(999911659\) 是个质数,不难想到欧拉定理,可以得到 \(G^{\sum_{d|n}{C^{d}_{n}}}\equiv\ G^{\sum_{d|n}C^{d}_{n}\ mod\ 999911658}\ (mod\ 999911659)\)。对于底数 \(G\) 和最终取模数 $mod $ \(999911659\) 可以直接用费马小定理求出。

所以现在需要解决的问题就是,如何求出 \(\sum_{d|n}{C^{d}_{n}\ mod\ 999911658}\)

这里需要用到中国剩余定理

先对 \(999911658\) 进行质因数分解 \(999911658=2\times3\times4697\times35617\)

将 \(\sum_{d|n}C^{d}_{n}\) 分别对 \(999911658\) 的四个质因数取模,构建同余方程组,求出在模通解 \(999911658\) 的通解 \(t\) ,那么 $ t=\sum_{d|n}C^{d}_{n}mod\ 999911658$

最终答案即为:\(G^{t}\ mod\) \(999911659\)

\(\begin{cases}
x\equiv \sum_{d|n}C^{d}_{n}(mod\ 2)\\
x\equiv \sum_{d|n}C^{d}_{n}(mod\ 3)\\
x\equiv \sum_{d|n}C^{d}_{n}(mod\ 4679)\\
x\equiv \sum_{d|n}C^{d}_{n}(mod\ 35617)\\
\end{cases}\)

然后接着可以用Lucas定理求解,就做完了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath> #define rint register int
#define endl '\n'
#define int long long const int Mod = 999911659;
const int mod = 999911658;
const int N = 4e4 + 5; int n, g;
int d[N], tot;
int p[10], cnt;
int fac[N], inv[N];
int a[10]; int qpow(int a, int b, int p)
{
int res = 1;
for (; b; b >>= 1)
{
if (b & 1)
{
res = (res * a) % p;
}
a = (a * a) % p;
}
return res;
} void init(int p)
{
fac[0] = inv[0] = 1;
for (rint i = 1; i < p; i++)
{
fac[i] = fac[i - 1] * i % p;
inv[i] = qpow(fac[i], p - 2, p);
}
} int C(int n, int m, int p)
{
if (m > n)
{
return 0;
}
return (inv[m] * inv[n - m] % p) * fac[n] % p;
} int lucas(int n, int m, int p)
{
if (!m)
{
return 1;
}
return C(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
} int CRT()
{
int ans = 0;
for (rint i = 1; i <= cnt; i++)
{
int M = mod / p[i];
int t = qpow(M, p[i] - 2, p[i]);
//关于这个为什么求出来的是方程的解到现在也不太懂,之前都是用的exgcd
ans = (ans + t * M * a[i] % mod) % mod;
}
return ans;
} void calc(int x)
{
init(p[x]);
for (rint i = 1; i <= tot; i++)
{
a[x] = (a[x] + lucas(n, d[i], p[x])) % p[x];
}
} signed main()
{
scanf("%lld%lld", &n, &g); if (g % Mod == 0)
{
puts("0");
return 0;
} int t = mod;
for (rint i = 2; i <= sqrt(mod); i++)
{
if (!(t % i))
{
p[++cnt] = i;
while (t % i == 0)
{
t /= i;
}
}
} if (t != 1)
{
p[++cnt] = t;
} for (rint i = 1; i <= sqrt(n); i++)
{
if (!(n % i))
{
d[++tot] = i;
if (i * i != n)
{
d[++tot] = n / i;
}
}
} for (rint i = 1; i <= cnt; i++)
{
calc(i);
} printf("%lld", qpow(g, CRT(), Mod)); return 0;
}

[HNOI2002] 跳蚤

设题目中的那个长度为 \(n+1\) 的序列为 \(\{a_1...a_n,m\}\),这个题就是在求使 \(\sum_{i=1}^{n}a_i\times x_i+m\times x_{n+1}=1\) 有解的 \(a_1,a_2...a_n\) 有多少种。

\(Bézout\) 定理,可得方程的有解情况就是 \(\gcd(a_1,a_2...a_n,m)=1\)

但是直接去找方程有解的情况很麻烦且很难,可以反向考虑,求出上面那个方程无解的情况。

无解时,\(\gcd(a_1,a_2...,a_n,m)\not=1\)

先把 \(m\) 分解质因数,\(a_1...a_n\) 都一定有一个共同的 \(n\),就能算出使它无解的方案数了。

但是求无解显然有重复的情况,这个时候可以容斥原理,当 \(a_i\) 都为 \(x\) 的倍数时,此时方案数就是 $(\frac{m}{x})^{n} $

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath> #define rint register int
#define endl '\n'
#define int long long const int N = 1e2 + 5; int n, m, cnt;
int a[N];
int ans; signed main()
{
scanf("%lld%lld", &n, &m);
ans = pow(m, n);
int k = m; for (rint i = 2; i <= sqrt(m); i++)
{
if (m % i == 0)
{
a[++cnt] = i;
while (m % i == 0)
{
m /= i;
}
}
} if (m > 1)
{
a[++cnt] = m;
} for (rint i = 1; i < 1 << cnt; i++)
{
int val = 1, num = 0;
for (rint j = 1; j <= cnt; j++)
{
if (i & (1 << (j - 1)))
{
num++;
val *= a[j];
}
}
if (num % 2)
{
ans -= pow(k / val, n);
}
else
{
ans += pow(k / val, n);
}
} printf("%lld\n", ans); return 0;
}

「KDOI-02」 一个仇的复

不难发现,肯定是由一堆横着的和一些竖着 \(2 \times 1\) 的构成的,而竖着的将将原来的网格分成了若干段。

只有一行时,设长度为 \(n\),用了 \(m\) 块。答案就是 \(\dbinom {n-1} {m-1}\)。拓展到两个并列的一行(即两行),答案是 \(\dbinom {2n-2} {m-1}\)。

枚举有 \(i\) 个竖着的,其中有 \(j\) 段。

先考虑剩下的分成 \(n-i\) 段的方案。要求方案数,首先我们要知道能插的个数。这时需要分类讨论。

若竖着没有在开头和结尾的,那么能插的个数为 \(2(n-1-i-j)\),还要划分的段数是 \(m-2(j+1)-i\),那么方案就是 \(\dbinom {2(n-1-i-j)} {m-2(j+1)-i}\)

若竖着只有一个在开头结尾,那么能插的个数为 \(2(n-i-j)\),还要划分的段数是 \(m-2j-i\),那么方案就是 \(\dbinom {2(n-i-j)} {m-2j-i}\)

若竖着的都在开头和结尾,那么能插的个数为 \(2(n+1-i-j)\),还要划分的段数是 \(m-2(j-1)-i\),那么方案就是 \(\dbinom {2(n+1-i-j)} {m-2(j-1)-i}\)

接着考虑竖着的方案,发现这个直接用插板法很难求,那么考虑分步来求。先考虑划分为 \(j\) 段,这个直接插板求出,方案是 \(\dbinom {i-1} {j-1}\),再考虑把这 \(j\) 段再插到原来的网格中,可以插在剩下位置的前面,但是再第一个的前面就不行,所以方案是 \(\dbinom {n-i-1} {j/j-1/j-2}\),下面取决于上面的分裂讨论,那么总的方案就是乘积。

考虑枚举有 \(i\) 个竖着的,其中有 \(j\) 段的方案就是三种情况的和乘上竖着的方案。

由于此题数据较大,卡不过去,所以只写了个 70pts 的代码:

#include <iostream>
#include <cstdio>
#include <algorithm> #define rint register int
#define endl '\n'
#define int long long using namespace std; const int N = 4e7 + 5;
const int M = 5e3 + 5;
const int mod = 998244353; int n, m, inv[N], fac[N]; int qpow(int a, int b)
{
int res = 1;
for (;b ;b >>= 1)
{
if (b & 1)
res = res * a % mod;
a = a * a % mod;
}
return res;
} void init()
{
fac[0] = inv[0] = 1;
for (rint i = 1; i <= 10000000; i++)
{
fac[i] = fac[i - 1] * i % mod;
inv[i] = qpow(fac[i], mod - 2);
}
} int C(int n, int m)
{
return (inv[m] * inv[n - m] % mod) * fac[n] % mod;
} signed main()
{
scanf("%lld%lld", &n, &m);
init();
int ans = C(2 * (n - 1), m - 2);
for (rint i = 1; i <= m; i++)
{
for (rint j = 1; j <= i; j++)
{
int tmp = j + 1;
if (tmp * 2 + i <= m)
{
int now1 = n - 1 - i - j;
int now2 = m - (tmp * 2 + i);
int res = C(i - 1, j - 1) * C(n - i - 1, j) % mod * C(2 * now1, now2) % mod;
ans = (ans + res) % mod;
}
tmp = j;
if (tmp * 2 + i <= m)
{
int now1 = n - i - j;
int now2 = m - (tmp * 2 + i);
int res = 2 * C(i - 1, j - 1) * C(n - i - 1, j - 1)%mod * C(2 * now1, now2)%mod;
ans = (ans + res) % mod;
}
tmp = j - 1;
if (tmp * 2 + i <= m && j >= 2)
{
int now1 = n + 1 - i - j;
int now2 = m - (tmp * 2 + i);
int res = C(i - 1, j - 1) * C(n - i - 1, j - 2) % mod * C(2 * now1, now2) % mod;
ans = (ans + res) % mod;
}
}
} printf("%lld\n", ans + (n == m)); return 0;
}

CSP-S 考前数学练习的更多相关文章

  1. CSP2019心路历程

    --人常说无论做什么都不要忘了初心,但如果一个人从来没有"应该"去忘了初心,又从何谈起的初心. CSP开考前,风吹在脸上,一些淡淡的回忆化作影子碎在地上:是到了一个令人感伤的路口了 ...

  2. CSP考前复习

    前言 因为loceaner太菜了,他什么东西都不会 所以他打算学一个东西就记录一下 不过因为他很菜,所以他不会写原理-- 而且,他希望在2019CSP之前不会断更 就酱紫,就是写给他自己的--因为他太 ...

  3. noip2017考前基础复习——数论数学

    ·最大公约数 gcd 辗转相除法  gcd(a,b)=gcd(b,a%b) int gcd(int x,int y){ ) return x; return gcd(y,x%y); } 效率O(log ...

  4. NOIP&CSP 考前 Dev-cpp 的选项问题和考试心态

    (进入考场后您将获得一个崭新的 \(Dev-cpp\),没有中文,没有编译选项,没有缺省源:我还将获得一个崭新的脑子,没有心态,没有智商,没有调试能力--) 中文 \[Step1 \] \[Step2 ...

  5. csp考前

    T1不会太麻烦,不行心里多说几遍"沙比提,沙比提".就做出来了. 后天就要出发了,可是我感觉不到长进---- 可能又学一年是个不明智的想法,退役预定.

  6. 【CSP模拟赛】Confess(数学 玄学)

    题目描述 小w隐藏的心绪已经难以再隐藏下去了.小w有n+ 1(保证n为偶数)个心绪,每个都包含了[1,2n]的一个大小为n的子集.现在他要找到隐藏的任意两个心绪,使得他们的交大于等于n/2. 输入描述 ...

  7. 【CSP模拟赛】坏天平(数学&思维)

    蹭兄弟学校的题目做还不用自己出题的感觉是真的爽 题目描述 nodgd有一架快要坏掉的天平,这架天平右边的支架有问题,如果右边的总重量比左边多太多,天平就彻底坏掉了.现在nodgd手上有n种砝码,质量分 ...

  8. 【CSP模拟赛】方程(数学)

    题目描述 求关于x的方程:x1+x2+……xk=n的非负整数解的个数. 输入格式 仅一行,包含两个正整数n,k. 输出格式 一个整数,表示方程不同解的个数,这个数可能很大,你只需输出mod 20080 ...

  9. CSP考前总结

    10.2 考试: 1.数位DP 或者找规律 2.SB题,扫一遍找最大最小即可 3.莫比乌斯反演 出题人相出个数论和数据结构的综合题,但是找不到NOIP级别的,没办法只能忍痛割爱出个莫比乌斯,话说回来, ...

  10. 【csp模拟赛5】限制 (restrict.cpp)--数学

    自己看吧: 爆搜代码: //春水初涨-春林初盛-春风十里-不如你 //----hzwer // 这是啥子题,读不懂-- //题意有问题 -- #include<iostream> #inc ...

随机推荐

  1. 【工具推荐】github打不开or加载慢?不用配置hosts,教你一键加速!

    不说废话 下载watt toolkit(原名steam++) 官方地址: Watt Toolkit - 瓦特工具箱(Steam++官网) (steampp.net) 安装完后选中,点击一键加速即可. ...

  2. [jmeter]快速入门

    前言 以压测一个api为例.假设有一个非常简单的api http://192.168.1.111:8080/,只是返回 helloworld 字符串. 准备 打开 jmeter,新建测试计划 在测试计 ...

  3. CentOS7更新OpenSSH

    前言 整个过程不要断开ssh链接,如有必要可使用telnet远程操作. 系统版本:centos 7.9 OpenSSL版本:1.0.2k -> 1.1.1q OpenSSH版本:7.4p1 -& ...

  4. 自定义组件使用v-model

    场景描述 我们在一个系统中,会出现这样的情况, 有一个联系人的下拉框,这个下拉框中的数据是从服务端获取的. 在很多页面都需要使用这个联系人(下拉框). 我们通常是这样做的: 写一个下拉框组件然后调用接 ...

  5. 数据api接口就是应用集成吗?

    ​ 数据 API 接口和应用集成是两个不同的概念,但是它们之间有一定的联系.数据 API 接口是一种用于访问和传输数据的标准化接口,而应用集成则是将不同的应用程序和系统整合在一起,实现数据和业务流程的 ...

  6. 深入了解商品详情API接口的使用方法与数据获取

    ​ 作为程序员,了解和熟悉如何调用API接口获取淘宝商品数据是非常重要的.在现今的电商环境中,准确.及时地获取商品详情信息对于开发者和商家来说至关重要.本文将以程序员的视角,详细介绍如何调用API接口 ...

  7. php-fpm的配置

    pass 对应的php-fpm socket,这样nginx就能将请求转发给php-fpm,这个的实现真的是精彩,为什么,因为php-fpm是负责管理多个php进程的,他的稳定性令人赞叹. index ...

  8. 安卓APK签名注入大师(APP注入弹窗,注入打开密码,注入过期时间, 注入提示信息,一机一码)

    安卓APK签名注入大师可以给安卓APK文件一键注入APP注入弹窗,注入打开密码,注入过期时间, 注入提示信息,一机一码等功能,方便开发人员给自己的APK文件添加消息提示, 密码等功能. 可以保护文件安 ...

  9. 遥遥领先.NET 7, .NET 8 性能大幅提升

    每个版本必有的性能提升汇总文章又来了.大家可以学习阅读了. 微软 .NET 开发团队的工程师 Stephen Toub 发表博客<Performance Improvements in .NET ...

  10. 基于go语言gin框架的web项目骨架

    该骨架每个组件之间可单独使用,组件之间松耦合,高内聚,组件的实现基于其他三方依赖包的封装. 目前该骨架实现了大多数的组件,比如事件,中间件,日志,配置,参数验证,命令行,定时任务等功能,目前可以满足大 ...