2022 杭电多校(2) 补题 2, 9, 12 , 8
2 C++ to Python 水题
签到,只要无视字母、下划线、冒号后输出即可
9 ShuanQ 逆元
题意:
已知
M是质数,\(P × Q ≡ 1\,\,\, mod\, M\)。
加密公式:
\(encrypted_{data} = raw_{data} \times P \mod M\)
解密公式:
\(raw_{data} = encrypted_{data} \times Q \mod M\)
给P和Q以及\(encrypted_{data}\),求加密前的原始数据\(row_{data}\)。
题解:
由
\(P × Q ≡ 1\,\,\, mod\, M\)
可得\(P × Q − 1 = k × M, k ≥ 1\)
证明
即:M是kM的一个比P,Q大的质因子。
而且显然最多只有一个质因子满足要求。
问题就变成了求解\(min(P,Q)\)到\(P × Q − 1\)的一个质因子M
求出m后,按照题目给的公式正常计算即可。
代码:
#include <iostream>
#include <cstring>
#include <vector>
#include <bits/stdc++.h>
#define endl '\n'
//#pragma GCC optimize(3)
#define int long long
#define pii pair<int, int>
using namespace std;
const int N = 1e6 + 10;
int getmaxprime(int n)
{
for (int i = 2; i <= sqrt(1.0 * n); i++)
{
while (n % i == 0)
n = n / i;
}
return n;
}
int p, q, e;
void solve()
{
cin >> p >> q >> e;
int m = getmaxprime(p * q - 1);
// cout<<k<<endl;
if (m <= p || m <= q || m <= e)
{
cout << "shuanQ" << endl;
}
else
{
cout << ((e % m) * (q % m) + m) % m << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
12 Luxury cruise ship 背包 数学
题意:
Kayzin 每天会将 7 或 31 或 365 个硬币放入他的存钱罐中。
现在 Kayzin 想知道他至少需要多少天才能“准确地”(不多也不少)凑齐购买豪华游轮的钱。
如果 Kayzin 不能“完全”凑齐购买豪华游轮的钱,打印 -1。
题解:
有一个定义:
两个质数x,y可以通过\(ax+by\)(a和b是任意整数)组成大于\(x × y-x-y\)的任何一个整数。
通过这个定理可以发现:365可以由7和31这两个质数组成。
因此如果N较大,先用 365 将 N 减小到背包预处理的范围内,然后剩余的部分进行背包。
代码:
#include <iostream>
#include <cstring>
#include <vector>
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<int, int>
using namespace std;
int n, m, t;
string st, ans;
int x, y;
int min(int a, int b)
{
if (a < b)
return a;
else
return b;
}
int dp[600];
int a[3] = {7, 31, 365};
void solve()
{
cin >> t;
while (t--)
{
x = 0, y = 0;
cin >> n;
for (int i = 1; i <= 600; i++)
dp[i] = 0x3f3f3f3f3f;
int cnt = 0;
int tmp = (n - 180) / 365;
int res = n;
if (tmp > 0)
{
res -= tmp * 365;
cnt += tmp;
}
for (int i = 0; i < 3; i++)
{
for (int j = a[i]; j <= res; j++)
{
dp[j] = min(dp[j - a[i]] + 1, dp[j]);
}
}
if (dp[res] == 0x3f3f3f3f3f)
cout << -1 << endl;
else
cout << dp[res] + cnt << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}
8 Keyboard Warrior 哈希
题意:
给定一个操作序列 ( c , k ),若 c 为小写字符则往缓冲区添加 k 个 c c字符;若为 -则删除最后的 k 个字符。问是否存在一个时刻,给定的一个串 S 为缓冲区中字符串的一个连续子串。
思路:
使用哈希算法来比较两个字符串是否相同,然后模拟过程即可。
然后哈希算法如果按照正常的哈希算法,需要注意
一次性加入 k 个字符 ch 的哈希值,通过等比数列公式可以得到为\(ch × \dfrac{p^k-1}{p-1}\),可以\(\mathcal O(1)\) 的计算。
如果按照标程,就是没有这个问题。
标程的哈希公式:\(hash[i]= hash[i-1]+ch * Base + k\)
#include <iostream>
#include <cstring>
#include <vector>
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define pii pair<char, int>
#define ull unsigned long long
using namespace std;
const int N = 1e6 + 10;
const ull B = 131;
string s;
ull f[N];
pii stk[N];
void solve()
{
int n, m;
cin >> n >> m;
cin >> s;
s = '1' + s;
int dif = 1;
for (int i = 2; i <= n; i++)
if (s[i] != s[i - 1])
dif++;
int be_len = 0, en_len = 0;
for (int i = 1; i <= n && s[i] == s[1]; i++)
be_len++;
for (int i = n; i >= 1 && s[i] == s[n]; i--)
en_len++;
ull key = 0;
for (int i = be_len + 1; i <= n - en_len;)
{
ull j = 1;
while (s[i] == s[i + 1])
++j, ++i;
key += s[i] * B + j;
++i;
}
int p = 0;
int flag = 0;
char ju;
int num;
while (m--)
{
cin >> ju >> num;
if (num == 0)
continue;
if (ju == '-')
{
while (num && p)
{
if (stk[p].second > num)
stk[p].second -= num, num = 0;
else
num -= stk[p].second, p--;
}
}
else
{
if (p && stk[p].first == ju)
stk[p].second += num;
else
stk[++p] = {ju, num};
}
if (p)
f[p] = f[p - 1] + (stk[p].first * B + stk[p].second);
if (dif == 1 && stk[p].second >= be_len)
flag = 1;
if (dif != 1 && p >= dif &&
stk[p - dif + 1].first == s[1] && stk[p - dif + 1].second >= be_len &&
stk[p].first == s[n] && stk[p].second >= en_len &&
f[p - 1] - f[p - dif + 1] == key)
{
flag = 1;
}
}
if (flag)
cout << "yes" << endl;
else
cout << "no" << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t = 1;
// cout << "ss" << endl;
cin >> t;
while (t--)
solve();
return 0;
}