部分題目列表:
題號 | 題目 | 算法 |
---|---|---|
B題 | 密碼學 | 簽到題,字符串處理 |
H題 | 最大公約數 | 數學、gcd、大數 |
F題 | 乘法 | 較爲巧妙的使用二分 |
A題 | 期望逆序對 | - |
C題 | 染色圖 | - |
I題 | K小數查詢 | 在線線段樹套權值線段樹 |
B題 密碼學
簽到題,就是一個字符串的計算,可恥的WA了一發是因爲忘記了解碼要倒着去解( 從 到 )
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1005;
int a[maxn], b[maxn];
string str[maxn];
int s[maxn][105];
void dde(int k)
{
for (int i = 0; i < str[k].size(); i++) {
if (str[k][i] > 'Z')
s[k][i] = str[k][i] - 'a';
else
s[k][i] = str[k][i] - 'A' + 26;
}
}
int main(void)
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++)
scanf("%d%d", &a[i], &b[i]);
for (int i = 1; i <= n; i++)
cin >> str[i];
for (int i = m - 1; i >= 0; i--) {
int x = a[i], y = b[i];
string aa = str[x], bb = str[y];
while (str[x].size() < str[y].size())
str[x] = str[x] + str[x];
for (int j = 0; j < str[y].size(); j++) {
dde(x), dde(y);
int kkk = s[y][j] - s[x][j];
kkk = (kkk + 52) % 52;
if (kkk < 26)
bb[j] = kkk + 'a';
else
bb[j] = kkk - 26 + 'A';
}
str[x] = aa;
str[y] = bb;
}
for (int i = 1; i <= n; i++)
cout << str[i] << endl;
return 0;
}
H題 最大公約數
Java大數走起
題幹:有三個人 ,其中 和 共享了一個神祕的數字 ,已知 , 現在 和 說:“ 的值等於 ”。
不太信任 ,於是想向 確認一下 是否真的等於 。 雖然不想直接把 的值告訴 ,但是 允許 給出一個正整數 (注意 可以大於 ),然後 會回答 。
現在給出 ,你需要幫助 決定這樣的 的取值,使得 一定可以通過 的回答來判斷 有沒有撒謊。如果這樣的 有多個,你需要輸出最小的那個。
輸入第一行是一個整數 。
對於每組數據,輸入一行兩個整數 。
對於每組數據,輸出一行一個整數,表示答案。如果滿足條件的 不存在,則輸出 −1。
// package Main;
import java.util.*;
import java.math.*;
public class Main {
static BigInteger arr[] = new BigInteger[505];
static BigInteger m(int a) {
return new BigInteger(a + "");
}
static boolean isP(int x) {
for (int i = 2; i * i <= x; i++)
if (x % i == 0)
return false;
return true;
}
static void init() {
arr[1] = BigInteger.ONE;
for (int i = 2; i <= 500; i++) {
if (isP(i))
arr[i] = arr[i - 1].divide(arr[i - 1].gcd(m(i))).multiply(m(i));
else
arr[i] = arr[i - 1];
}
}
public static void main(String[] args) {
init();
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while (t-- != 0) {
int n = sc.nextInt();
int k = sc.nextInt();
BigInteger ans = arr[n / k].multiply(m(k));
System.out.println(ans);
}
}
}
F題 乘法
題意:給出一個長度爲 的數列和一個長度爲 的數列, 可以構造得到一個 的矩陣 ,其中 , 給出整數 ,你需要求出 中第 大的數的值。(, )
思路:二分的找,需要額外注意當數爲負數和零時候的情況
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
typedef long long ll;
const int maxn = 1e5 + 5;
ll ef = 1e12;
ll n, m, k;
vector<ll> a, b;
ll update_a(ll x, ll mid, ll l, ll r)
{
if (l == r)
return l;
int m = (l + r + 1) >> 1;
if (x * b[m] <= mid)
return update_a(x, mid, m, r);
else
return update_a(x, mid, l, m - 1);
}
ll update_b(ll x, ll mid, ll l, ll r)
{
if (l == r)
return l;
int m = (l + r) >> 1;
if (x * b[m] <= mid)
return update_b(x, mid, l, m);
else
return update_b(x, mid, m + 1, r);
}
ll Binary_Search(ll l, ll r)
{
if (l == r)
return l;
ll mid = (l + r) >> 1;
ll ans = 0;
for (int i = 0; i < a.size(); i++) {
if (a[i] < 0)
ans += m - update_b(a[i], mid, 0, b.size());
else
ans += update_a(a[i], mid, -1, b.size() - 1) + 1;
}
if (ans >= k)
return Binary_Search(l, mid);
else
return Binary_Search(mid + 1, r);
}
int main(void)
{
IO;
cin >> n >> m >> k;
k = n * m - k + 1;
ll tmp;
for (int i = 0; i < n; i++) {
cin >> tmp;
a.push_back(tmp);
}
for (int i = 0; i < m; i++) {
cin >> tmp;
b.push_back(tmp);
}
sort(a.begin(), a.end());
sort(b.begin(), b.end());
cout << Binary_Search(-ef, ef) << endl;
return 0;
}
A題 期望逆序對
題意:生成一個每個數是從 中生成的整數, 中不存在相同的數字,求逆序對個數的期望的最小值, 數組範圍至.
輸出一行一個整數,表示答案對 998244353 取模後的值。假設答案的最簡分數表示是 , 你需要輸出一個整數 滿足
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int maxn = 5050;
struct section {
int l, r;
void read() {
scanf("%d%d", &l, &r);
}
bool operator < (const section& s1) {
return l + r < s1.l + s1.r;
}
}a[maxn];
int n, b[maxn];
int quick(int x, int y)
{
int z = 1;
while (y) {
if (y & 1)
z = 1ll * z * x % mod;
y >>= 1;
x = 1ll * x * x % mod;
}
return z;
}
int cal(section x, section y)
{
int l = max(x.l, y.l);
if (l > x.r)
return 0;
int r = min(x.r, y.r);
int ans = 1ll * (l - y.l + r - y.l) * (r - l + 1) / 2 % mod;
ans = (ans + 1ll * (x.r - r) * (y.r - y.l + 1)) % mod;
return ans;
}
int main(void)
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
a[i].read();
sort(a + 1, a + n + 1);
int ans = 0;
for (int i = 1; i <= n; i++)
b[i] = quick(a[i].r - a[i].l + 1, mod - 2);
for (int i = 1; i <= n; i++)
for (int j = i + 1; j <= n; j++)
ans = (ans + 1ll * b[i] * b[j] % mod * cal(a[i], a[j])) % mod;
printf("%d\n", ans);
return 0;
}
C題 染色圖
—待補—
I題 K小數查詢
樹套樹之線段樹套權值線段樹,在線維護
—待補—