2021.5.4QBXT数学专题模拟赛
写在前面
si~
有点舒服~
你们班这题要是让我去我不 AK 全场??
—— CAQ
颁奖刚好卡到 11 名,结果是个辣鸡无线鼠标,太敷衍了。。。羡慕 rank 1 的游戏键盘/se
被一个黑黑胖胖的小朋友吊打了。。。
得分情况
期望得分 | 实际得分 | |
---|---|---|
T1 | \(100\) | \(100\) |
T2 | \(100\) | \(50\) |
T3 | \(30\) | \(30\) |
T4 | \(30\) | \(30\) |
总 | \(260\) | \(210\) |
排名:11
T1
题目描述
给定 \(x,y\) ,求 \(x\bmod y\)。
输入格式
一行两个整数\(x,y\)。
输出格式
输出一行一个整数代表答案。
样例
输入
233 23
输出
3
提示
对于 \(40\%\) 的数据,\(1\leq x,y\leq10^7\)。
对于 \(80\%\) 的数据,\(1\leq x\leq 10^{100},1\leq y\leq 10^7\)。
对于 \(100\%\) 的数据, \(1\leq x\leq10^{100000},1\leq y\leq 2^{31}\) 。
思路
考场思路
注意到数据范围非常大,考虑高精度。
但是题目要求进行模运算,可以 \(x\) 以字符串形式读入,然后在转换数字过程中进行取模。
即边读边模。
对快读进行一通魔改即可。
/*
Name: #1.一
Solution: 高精,边读边模
By Frather_
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
/*===============================================定义变量*/
char x[100010];
int y;
/*=============================================自定义函数*/
inline int read()
{
int X = 0, F = 1;
for (int i = 0; i < strlen(x);)
{
char CH = x[i];
while (CH < '0' || CH > '9')
{
if (CH == '-')
F = -1;
i++;
CH = x[i];
}
while (CH >= '0' && CH <= '9')
{
X = ((X << 3) % y + (X << 1) % y + (CH ^ 48) % y) % y;
i++;
CH = x[i];
}
}
return X * F % y;
}
/*=================================================主函数*/
signed main()
{
cin >> x >> y;
printf("%lld\n", read());
return 0;
}
正解思路
将 \(x\) 以字符串形式读入,然后逐位将其转化取模。
核心操作与边读边模类同。
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int m;
char s[100010];
int main()
{
scanf("%s", s + 1);
scanf("%d", &m);
int l = strlen(s + 1);
long long ans = 0;
for (int a = 1; a <= l; a++)
ans = (ans * 10 + s[a] - '0') % m;
printf("%lld\n", ans);
return 0;
}
T2
题目描述
大小为 \(3\times N\) 的方格图,你需要用有\(M\)种颜色的大小为 \(1\times 1\) 和 \(2\times 2\) 的小方块去覆盖整个方格图。小方块和小方块之间不能互相覆盖,并且必须将整个方格图全部覆盖。求有多少种覆盖方格图的方法。两种方案不一样当且仅当存在某个位置颜色不一样或者摆放小方块的方法不一样。
输入格式
第一行两个整数 \(N,M\)。
输出格式
一行一个整数代表答案对 \(10^9+7\) 取模的结果。
样例
输入
2 2
输出
80
提示
如果全部用 \(1\times 1\) 的小方块,不考虑颜色只有一种摆放方法,考虑颜色方案数为 \(64\) 。
如果用一个 \(2\times 2\) 的小方块,不考虑颜色有两种摆放方法,考虑颜色方案数为 \(16\) 。
对于 \(30\%\) 的数据, \(1\leq N,M\leq 5\) 。
对于另外 \(20\%\) 的数据, \(M=1\) 。
对于另外 \(20\%\) 的数据, \(N\leq10^6\) 。
对于 \(100\%\) 的数据, \(1\leq N,M\leq10^9\) 。
思路
考场思路
不难得出如下递推式:
然后注意到数据范围过大,考虑矩阵加速递推,
计算得到 \(base\) 矩阵
初始化 \(ans\) 矩阵
有了这两个矩阵以后直接矩阵计算即可。
其实这题实际上也就是 广义上的斐波那契数列 。
/*
Name: #2.二
Solution: 矩阵加速 递推
f(n) = m^3 (f(n - 1) +2f(n - 2) )
By Frather_
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
// #define kMod 1000000007
const int kMod = 1e9 + 7;
using namespace std;
/*====================================================*/
inline int read()
{
int X = 0, F = 1;
char CH = getchar();
while (CH < '0' || CH > '9')
{
if (CH == '-')
F = -1;
CH = getchar();
}
while (CH >= '0' && CH <= '9')
{
X = (X << 3) + (X << 1) + (CH ^ 48);
CH = getchar();
}
return X * F;
}
/*===============================================定义变量*/
int n, m;
struct Matrix
{
int a[3][3];
Matrix()
{
memset(a, 0, sizeof a);
}
} ans, base;
Matrix operator*(const Matrix &a, const Matrix &b)
{
Matrix res;
for (int i = 1; i <= 2; ++i)
for (int k = 1; k <= 2; ++k)
for (int j = 1; j <= 2; ++j)
res.a[i][j] = (res.a[i][j] + a.a[i][k] * b.a[k][j]) % kMod;
return res;
}
/*=============================================自定义函数*/
int Qpow(int a, int p)
{
int res = 1;
while (p)
{
if (p & 1)
res = res * a % kMod;
a = a * a % kMod;
p >>= 1;
}
return res;
}
void prepare()
{
ans.a[1][1] = (Qpow(m, 3) % kMod * 2 + Qpow(m, 6) % kMod) % kMod;
ans.a[1][2] = Qpow(m, 3) % kMod;
base.a[1][1] = 1 * Qpow(m, 3) % kMod;
base.a[1][2] = 1;
base.a[2][1] = 2 * Qpow(m, 3) % kMod;
base.a[2][2] = 0;
}
Matrix qPow(Matrix x, int p)
{
Matrix res;
for (int i = 1; i <= 2; ++i)
res.a[i][i] = 1;
while (p)
{
if (p & 1)
res = res * x;
x = x * x;
p >>= 1;
}
return res;
}
/*=================================================主函数*/
signed main()
{
n = read();
m = read();
prepare();
if (n == 1)
{
printf("%lld\n", ans.a[1][2]);
return 0;
}
if (n == 2)
{
printf("%lld\n", ans.a[1][1]);
return 0;
}
ans = ans * qPow(base, n - 2);
printf("%lld\n", ans.a[1][1] % kMod);
return 0;
}
/*
样例1:
2 2
80
*/
/*
样例2:
3 1
5
*/
正解思路
窝就是正解!!!
nyy才是。。。/kk
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
const int mo = 1000000007;
int n, m;
struct matrix
{
int z[2][2];
matrix()
{
memset(z, 0, sizeof(z));
}
} m1, m2;
matrix operator*(const matrix &m1, const matrix &m2)
{
matrix m3;
for (int a = 0; a < 2; a++)
for (int b = 0; b < 2; b++)
for (int c = 0; c < 2; c++)
m3.z[a][c] = (m3.z[a][c] + 1ll * m1.z[a][b] * m2.z[b][c]) % mo;
return m3;
}
int main()
{
scanf("%d%d", &n, &m);
if (n == 1)
printf("%lld\n", 1ll * m * m % mo * m % mo);
else
{
m1.z[0][0] = 1;
m1.z[0][1] = 1ll * m * m % mo * m % mo;
m2.z[0][0] = 0;
m2.z[1][0] = 1;
m2.z[0][1] = 2ll * m * m % mo * m % mo;
m2.z[1][1] = 1ll * m * m % mo * m % mo;
while (n)
{
if (n & 1)
m1 = m1 * m2;
m2 = m2 * m2;
n >>= 1;
}
printf("%d\n", m1.z[0][0]);
}
return 0;
}
小结
至于为什么有正解还只拿了 \(50 pts\) 呢,是因为某个大神笔赛时认为所谓快速幂,只不过是为了加速运算罢了,全然忽略了计算快速幂过程中可以边乘边模防止数据过大爆炸,所以在 prepare()
函数初始化矩阵时直接 m*m*m*m*m*m
完美爆炸丢分 \(50 pts\) 。
T3
题目描述
求
输入格式
第一行三个整数 \(x,n,m\)。
输出格式
一行一个整数代表答案。
样例
输入
3 3 3
输出
3
提示
对于 \(30\%\) 的数据,\(1\leq n,m\leq10\)。
对于 \(60\%\) 的数据,\(1\leq n,m\leq1000\)。
对于 \(100\%\) 的数据,\(1\leq x,n,m\leq10^5\)。
思路
考场思路
不会 Lucas。。不会 Lucas。。不会 Lucas。。。
算了直接暴力吧。。。
/*
Name: #3.三
Solution:
By Frather_
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 1000003471
using namespace std;
/*==================================================快读*/
inline int read()
{
int X = 0, F = 1;
char CH = getchar();
while (CH < '0' || CH > '9')
{
if (CH == '-')
F = -1;
CH = getchar();
}
while (CH >= '0' && CH <= '9')
{
X = (X << 3) + (X << 1) + (CH ^ 48);
CH = getchar();
}
return X * F;
}
/*===============================================定义变量*/
const int _ = 1000010;
int phi[_];
int x, n, m;
/*=============================================自定义函数*/
/*
void phi_table()
{
phi[0] = 0;
phi[1] = 1;
for (int i = 2; i < _ >> 1; ++i)
phi[i] = i;
for (int i = 2; i < _ >> 1; ++i)
if (phi[i] == i)
{
for (int j = i; j < _; j += i)
phi[j] = phi[j] / i * (i - 1);
}
}
*/
int calc(int a)
{
int res = 1;
for (int i = 1; i <= a; i++)
res = (res * i) % kMod;
return res % kMod;
}
int C(int a, int b)
{
return calc(a) / (calc(a - b) * calc(b));
}
int Qpow(int a, int p)
{
int res = 1;
while (p)
{
if (p & 1)
res = (res * a) % kMod;
a = (a * a) % kMod;
p >>= 1;
}
return res % kMod;
}
/*=================================================主函数*/
signed main()
{
x = read();
n = read();
m = read();
printf("%lld\n", Qpow(x, C(n, m)) % kMod);
return 0;
}
正解思路
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int kMod = 1000003471;
int pcnt, plist[10];
int x, n, m, C[1000][1000];
int gcd(int i, int b)
{
return b ? gcd(b, i % b) : i;
// if (!b)
// return i;
// else
// return gcd(b, i % b);
}
int Qpow(int i, int b, int kMod)
{
int ans = 1;
while (b)
{
if (b & 1)
ans = 1ll * ans * i % kMod;
i = 1ll * i * i % kMod;
b >>= 1;
}
return ans;
}
int get(int n, int m, int p)
{
C[0][0] = 1;
for (int i = 1; i < p; i++)
{
C[i][0] = 1;
for (int b = 1; b <= i; b++)
{
C[i][b] = C[i - 1][b - 1] + C[i - 1][b];
if (C[i][b] >= p)
C[i][b] -= p;
}
}
int ans = 1;
while (n || m)
{
ans = 1ll * ans * C[n % p][m % p] % p;
n /= p;
m /= p;
}
return ans;
}
void merge(int &v1, int &m1, int v2, int m2)
{
if (m1 < m2)
swap(v1, v2), swap(m1, m2);
while (v1 % m2 != v2)
v1 += m1;
m1 = m1 / gcd(m1, m2) * m2;
}
int work(int n, int m)
{
int v1 = 0, n1 = 1;
for (int i = 1; i <= pcnt; i++)
{
int v2 = get(n, m, plist[i]), n2 = plist[i];
merge(v1, n1, v2, n2);
}
return v1;
}
int main()
{
int v = kMod - 1;
for (int i = 2; i <= v; i++)
if (v % i == 0)
{
plist[++pcnt] = i;
while (v % i == 0)
v /= i;
}
scanf("%d%d%d", &x, &n, &m);
printf("%d\n", Qpow(x, work(n, m), kMod));
return 0;
}
T4
题目描述
给定 \(N\) 个数,其中第 \(i\) 个数为 \(\gcd(x,y+i-1)\) 。求任意一组可能的 \(x,y\) 的值。
输入格式
第一行一个整数 \(N\) 。
接下来一行 \(N\) 个整数。
输出格式
输出两个整数 \(x,y\) ,你需要保证 \(1\leq x,y\leq10^9\)。
样例
输入
3
2 3 2
输出
6 2
提示
对于\(30\%\)的数据,\(1\leq N\leq 5\),保证存在答案\(x,y\leq10\)。
对于另外\(20\%\)的数据,\(N=1\)。
对于另外\(20\%\)的数据,保证存在答案\(x,y\leq 1000\)。
对于\(100\%\)的数据,\(1\leq N\leq1000\),保证存在答案\(x,y≤10^9\)。
思路
考场思路
啊啊啊就还剩 \(5\) 分钟了。。。
哎? \(N = 1\) 可以骗分哇?直接暴力枚举符合条件输出完事。
荣获 \(30pts\) 耶!
/*
Name:
Solution:
By Frather_
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define int long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
inline int read()
{
int X = 0, F = 1;
char CH = getchar();
while (CH < '0' || CH > '9')
{
if (CH == '-')
F = -1;
CH = getchar();
}
while (CH >= '0' && CH <= '9')
{
X = (X << 3) + (X << 1) + (CH ^ 48);
CH = getchar();
}
return X * F;
}
/*===============================================定义变量*/
int x,y;
int n;
/*=============================================自定义函数*/
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
/*=================================================主函数*/
signed main()
{
n=read();
for(int i=1;i;i++)
for(int j=1;j;j++)
if(gcd(i,j+i-1)==n)
{
printf("%lld %lld\n",i,j);
return 0;
}
return 0;
}
正解
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
int n, z[1010];
int gcd(int a, int b)
{
if (!b)
return a;
else
return gcd(b, a % b);
}
void merge(int &v1, int &m1, int v2, int m2)
{
if (m1 < m2)
swap(v1, v2), swap(m1, m2);
while (v1 % m2 != v2)
v1 += m1;
m1 = m1 / gcd(m1, m2) * m2;
}
int main()
{
scanf("%d", &n);
for (int a = 1; a <= n; a++)
scanf("%d", &z[a]);
int x = 1;
for (int a = 1; a <= n; a++)
x = x / gcd(x, z[a]) * z[a];
int v1 = 0, m1 = 1;
for (int a = 1; a <= n; a++)
{
int v2 = ((1 - a) % z[a] + z[a]) % z[a];
int m2 = z[a];
merge(v1, m1, v2, m2);
}
printf("%d %d\n", x, v1);
return 0;
}
最后
有一说一,数学这方面代码是真的好写~
对于本次模拟赛,主要是 T2 \(50pts\) 丢分太遗憾,T3、T4 正解真想不到,水平有限,这样也就可以了吧。