[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. 这些年写过的花式sql - 第3句 今日流失用户

    第3句 今日流失用户 需求: 当日流失用户的定义:昨天登录的,今天没登录的用户数 有一张用户登录日志表,有字段 date_stamp(日期时间戳),用户id(uid).如果用户在某天登录了,该表会有一 ...

  2. 处理css/js兼容性的工具之超重要的browserslist

    这篇 webpack处理css资源 文章中使用到的工具 browserslist 对于兼容性处理来说非常重要!这一篇来仔细说说. 查询兼容性 不同浏览器对于 css / js 的属性可能存在兼容性,具 ...

  3. 让nodejs开启服务更简单--express篇

    上一篇文章说到,nodejs获取客户端请求需要我们自己去处理请求参数.请求方式等,而在express框架内部集成了很多好用的方法,我们不需要从0开始编写各种处理逻辑,这样可以极大提高我们的开发效率~ ...

  4. CSS基础(4)

    目录 1 定位 1.1 为什么需要定位 1.2 定位组成 1.2.1 边偏移(方位名词) 1.2.2 定位模式 (position) 1.3 定位模式介绍 1.3.1 静态定位(static) - 了 ...

  5. [刺客伍六七&黑客] 魔刀千刃

    魔刀千刃的特写 诞生之日:2023.7.29 此后会在此记录如何自己写一个自己的python库以及魔刀千刃的维护过程. 魔刀千刃(evilblade) **只攻不防,天下无双** 实战 (和堆攻击帖子 ...

  6. 【Windows】KMS 激活命令记录

    目录 KMS 服务器激活 Office.Visio 推荐使用 office tool plus 部署并配置 KMS 激活 什么是 KMS? KMS 正版与否的区别 总结 KMS 服务器激活 利用 KM ...

  7. 算术逻辑单元的实现(ALU)

    一.实验目的 掌握Vivado集成开发环境 掌握Verilog语言基本知识. 掌握并理解算术逻辑单元ALU的原理和设计 二.实验预习 1.ALU(算术逻辑单元)的16种运算的编码 三.模块接口设计 A ...

  8. win11安装ubuntu(by wsl2)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本机情况 省吃俭用入手了ThinkPad T14,打算 ...

  9. 【目标检测】Fast R-CNN算法实现

    一.前言 2014年,Ross Girshick提出RCNN,成为目标检测领域的开山之作.一年后,借鉴空间金字塔池化思想,Ross Girshick推出设计更为巧妙的Fast RCNN(https:/ ...

  10. Note -「virtual tree」shorter vrt

    Part. 1 Preface 没什么 preface. Part. 2 实现 具体来说就是把所有关键点按 \(\text{dfn}\) 排序,去重,然后求出相邻结点的 \(\text{LCA}\), ...