A
要想使最大元素最小,只需使得序列a的和最小,然后将最小和尽量平摊给每个数,最大的那个数便是答案。
因为a[i]是正整数,所以至少为1,所以序列a之和是大于等于n的。所以只需找到最小的 x 使得 x * k >= n,x * k便是最小和
AC代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;
#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);
LL n, m, k;
int main()
{
int T;
cin >> T;
while (T --)
{
cin >> n >> k;
LL sum = (n + k - 1) / k * k;
LL res = (sum + n - 1) / n;
cout << res << endl;
}
return 0;
}
B
(这题只能加,不能减,我就是一个看错题的憨憨)
设 s 为 p 的前缀和
对每个 p[i] 找到最小的 x 使得 100 * p[i] <= x * k,答案就是最大的 max(x, s[i - 1]) - s[i - 1]
AC代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;
#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, m, k;
LL p[N], s[N];
int main()
{
int T;
cin >> T;
while (T --)
{
cin >> n >> k;
for (int i = 1; i <= n; i ++)
{
cin >> p[i];
s[i] = s[i - 1] + p[i];
}
LL res = 0;
for (int i = 2; i <= n; i ++)
{
LL x = (p[i] * 100 + k - 1) / k;
res = max(res, x - s[i - 1]);
}
cout << res << endl;
}
return 0;
}
C
每个简单圆都有一个右边界,我们可以从 2 ~ n 枚举右边界 (1显然不能为右边界)
设 f[i] 为以第 i 条边为右边界的最大圆长度
当a[i] = b[i] 时 f[i] = c[i] - 1 + 2 (c[i] 是点数,c[i] - 1 才是边数)
否则 就有两种情况:
- 直接以第 i - 1 条线为左边界, 长度为: c[i] - 1 + 2 + abs(a[i] - b[i])
- 接在以第 i - 1 条线为右边界的圆后面,将 a[i] ~ b[i] 那一节线删去
则长度为: c[i] - 1 + 2 + f[i - 1] - abs(a[i] - b[i])两种情况取最大就是 f[i] 的值
AC代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;
#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, m, k;
LL a[N], b[N], c[N];
LL f[N];
int main()
{
int T;
cin >> T;
while (T --)
{
cin >> n;
for (int i = 1; i <= n; i ++)
scanf("%d", &c[i]);
for (int i = 1; i <= n; i ++)
scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++)
scanf("%d", &b[i]);
LL res = 0;
f[0] = 0;
for (int i = 2; i <= n; i ++)
{
if (a[i] == b[i])
f[i] = c[i] + 1;
else
f[i] = max(c[i] + 1 + f[i - 1] - abs(a[i] - b[i]), c[i] + 1 + abs(a[i] - b[i]));
res = max(res, f[i]);
}
cout << res << endl;
}
return 0;
}
D
可以很轻易的发现,从 i 出发后还能回到 i, 那么从 i 出发能够到达的最多数量就变成了 i 左边能够到达的数量(包括自己) + i 右边能到达的数量(包括自己) - 1。
因为每经过一条边,所有边都要反向,那么实际上每个点所处的情况只有 2 种:
所有边为一开始的情况,所有边为反向后的情况
这时候解法的轮廓就已经出来了,以计算向左能够到达的最多数量为例:
设 f [ i ] [ j ] 是点 i 在起始情况为 j 的情况下能到达的最大数量(j = 0, 1)
如果在情况 j 下,i 能到达 i - 1, f [ i ] [ j ] = f [ i - 1] [ j ^ 1 ] + 1。
如果不能到达,那 f [ i ] [ j ] = 1。
AC代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;
#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N = 3e5 + 10;
const int M = 2e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, m, k;
int l[N], r[N];
int f_l[N][2], f_r[N][2];
int main()
{
//freopen("C:\\Users\\Super Yuxiao Guo\\Desktop\\Code_Place\\Data_Test\\data.in.txt", "r", stdin);
//freopen("C:\\Users\\Super Yuxiao Guo\\Desktop\\Code_Place\\Data_Test\\data.out.txt", "w", stdout);
int T;
cin >> T;
while (T --)
{
memset(l, 0);
memset(r, 0);
cin >> n;
for (int i = 1; i <= n; i ++)
{
char c;
cin >> c;
if (c == 'L') l[i] = 1;
else r[i - 1] = 1;
}
f_l[0][0] = f_l[0][1] = 1;
for (int i = 1; i <= n; i ++)
for (int j = 0; j < 2; j ++)
{
f_l[i][j] = 1;
if (l[i] ^ j) f_l[i][j] += f_l[i - 1][j ^ 1];
}
f_r[n][0] = f_r[n][1] = 1;
for (int i = n - 1; i >= 0; i --)
for (int j = 0; j < 2; j ++)
{
f_r[i][j] = 1;
if (r[i] ^ j) f_r[i][j] += f_r[i + 1][j ^ 1];
}
for (int i = 0; i <= n; i ++)
cout << f_l[i][0] + f_r[i][0] - 1 << ' ';
cout << endl;
}
return 0;
}
E
E题题意看了好长时间才看懂,给了 n 个串 和 m 个串,后面 m 个串每个串有一个匹配串编号为 mt,这个匹配串是前 n 个串里的。问前 n 个串是否有一个排列,使得那 m 个串每个串从这排列的第一个开始找,第一个能够成功匹配的串是初始编号为 mt 的那个串。感觉挺绕的。
解法:
当存在 mt 串与对应串不能成功匹配时,那么情况显然不存在。
匹配成功时,因为 mt 为第一个成功匹配的串,那么即使有其它能够与该串成功匹配的串,也应该放在 mt 后面,那么从 mt 向其他能够与该串匹配成功的串连一条有向边,表示 mt 之后才是它,那当出现环了之后就会变成我在我自己后面,这是不存在的情况,所以很明显,当边连完后是一个拓扑图,那就存在排列,否则不存在,然后拓扑的顺序也很明显是一个解。
还有一个问题就是如何去找与该串匹配的串有哪些,这里我用的 trie 树
不知道还有没有其他更好的方法
AC代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <stack>
#include <map>
//#include <unordered_map>
#include <vector>
#include <cmath>
//#include <ext/rope>
#include <set>
using namespace std;
//using namespace __gnu_cxx;
#define pair(a, b) make_pair(a, b)
#define memset(a, b) memset(a, b, sizeof a)
#define max(a, b) ((a) < (b) ? (b) : (a))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define fi first
#define se second
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
//typedef __int128 INT;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int N = 1e5 + 10;
const int NN = 2e7;
const int M = 7e5 + 10;
const int Mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int P = 13331;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, m, k;
int a[4 * N];
int h[N], e[NN], ne[NN], idx;
int d[N], id[N], cnt;
bool st[N];
string g[N];
vector<int> v;
int tr[4 * N][27], tot = 1;
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
bool check(string a, string b)
{
for (int i = 0; i < k; i ++)
if (a[i] != b[i] && a[i] != '_' && b[i] != '_')
return false;
return true;
}
void insert(string s, int x)
{
int p = 1;
for (int i = 0; s[i]; i ++)
{
int ch;
if (s[i] == '_') ch = 26;
else ch = s[i] - 'a';
if (tr[p][ch] == 0) tr[p][ch] = ++ tot;
p = tr[p][ch];
}
a[p] = x;
}
void search(string s, int p, int now)
{
if(now == k)
{
v.push_back(a[p]);
return ;
}
char c = s[now];
if (c == '_')
{
for (int i = 0; i < 27; i ++)
if (tr[p][i])
{
search(s, tr[p][i], now + 1);
}
}
else
{
if (tr[p][26]) search(s, tr[p][26], now + 1);
if (tr[p][s[now] - 'a']) search(s, tr[p][s[now] - 'a'], now + 1);
}
}
void bfs()
{
queue<int> q;
for (int i = 1; i <= n; i ++)
if (!d[i])
{
q.push(i);
}
cnt = 0;
while (q.size())
{
int t = q.front();
q.pop();
id[++ cnt] = t;
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (-- d[j] == 0) q.push(j);
}
}
}
int main()
{
memset(h, -1);
cin >> n >> m >> k;
for (int i = 1; i <= n; i ++)
{
cin >> g[i];
insert(g[i], i);
}
bool flag = true;
for (int i = 1; i <= m; i ++)
{
string s;
int x;
cin >> s >> x;
if (!flag) continue;
if (!check(s, g[x])) flag = false;
else
{
v.clear();
search(s, 1, 0);
for (int i = 0; i < v.size(); i ++)
if (v[i] != x)
{
d[v[i]] ++;
add(x, v[i]);
}
}
}
bfs();
if (cnt < n) flag = false;
if (!flag) cout << "NO" << endl;
else
{
cout << "YES" << endl;
for (int i = 1; i <= n; i ++)
cout << id[i] << ' ';
cout << endl;
}
return 0;
}