F.Infinite String Comparision
题目链接:https://ac.nowcoder.com/acm/contest/5666/F
分析:如果求两个字符串的长度的lcm的话,会爆内存。因此,尝试比较长度的两倍即可,根据周期性定理,如果长度等于(a + b - gcd(a, b)),如果两个字符串没有失配,那么这两个字符串是相等的。(a + b - gcd(a, b) <= min(2 * lena, 2 * lenb))
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int N = 100005;
int main()
{
string a, b;
while (cin >> a >> b)
{
int lena = a.size(), lenb = b.size();
if (lena > lenb)
{
int i = 0;
for (i = 0; i < lena * 2; ++i)
{
char na = a[i % lena];
char nb = b[i % lenb];
if (na < nb)
{
cout << "<" << endl;
break;
}
else if(na > nb)
{
cout << ">" << endl;
break;
}
}
if (i == 2 * lena) cout << "=" << endl;
}
else
{
int i = 0;
for (i = 0; i < lenb * 2; ++i)
{
char na = a[i % lena];
char nb = b[i % lenb];
if (na < nb)
{
cout << "<" << endl;
break;
}
else if (na > nb)
{
cout << ">" << endl;
break;
}
}
if (i == 2 * lenb) cout << "=" << endl;
}
}
return 0;
}
H.Minimum-cost Flow(费用流)
题目链接:https://ac.nowcoder.com/acm/contest/5666/H
分析:首先看到分数(frac{ui}{vi}),可以想到用(gcd)化简。可以看到数据范围非常大,如果每次询问都建立一次图跑费用流,那么就会超时。不妨假设(总流量为1),每条边的容量(frac{ui}{vi}),同时乘以(v),那么总流量则为(v),每条边的容量则为(u)。那么当我们跑完费用流后,算出(总费用除以/v),并且使用(gcd)化简,即可得到答案。(每次spfa都会得到一条增广路的费用,同时这条增广路的流量在每条边上都是等流量的),我们算出每条增广路的费用后,用一个前缀和维护费用的前缀和。
(path[a]:下标从0开始,表示第a + 1条增广路的费用)
(sum[a]:下标从1开始,表示前a条增广路的费用)
这些预处理出来的费用是容量为1的时候的费用。我们假设(v = a * u + b(b < u)),表示前a条的增广路的流量为a,第a + 1条增广路的流量为b,那么总的流量则为v,那么答案则为(ans = (sum[a] * u + path[a] * b) / v)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
using LL = long long;
const int N = 100, M = 55 * 55 * 2;
const LL inf = (1LL << 60);
int h[N], e[M], ne[M], w[M], idx;
//费用
LL cost[M];
//到某个点的费用
LL d[N], incf[N];
int pre[N];
bool st[N];
int n, m;
int s, t;
//最大流和最大费用
LL res, maxflow;
//每条增广路的费用和前缀和
vector<LL> path;
LL sum[N];
LL gcd(LL a, LL b)
{
return b ? gcd(b, a % b) : a;
}
//z:容量 c:单位费用
void add(int a, int b, int z, int c)
{
e[idx] = b, w[idx] = z, cost[idx] = c, ne[idx] = h[a], h[a] = idx++;
e[idx] = a, w[idx] = 0, cost[idx] = -c, ne[idx] = h[b], h[b] = idx++;
}
bool spfa()
{
queue<int> q;
//求最小费用
for (int i = s; i <= t; ++i)
d[i] = inf;
memset(st, 0, sizeof st);
q.push(s);
d[s] = 0, st[s] = true;
//增广路上各边的最小剩余容量
incf[s] = inf;
while (q.size())
{
int u = q.front();
q.pop();
st[u] = false;
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if (!w[i]) continue;
if (d[j] > d[u] + cost[i])
{
d[j] = d[u] + cost[i];
incf[j] = min(incf[u], (LL)w[i]);
pre[j] = i;
if (!st[j])
{
st[j] = true;
q.push(j);
}
}
}
}
if (d[t] == inf) return false;
return true;
}
void update()
{
int u = t;
while (u != s)
{
int i = pre[u];
w[i] -= incf[t];
w[i ^ 1] += incf[t];
u = e[i ^ 1];
}
//一条增广路的总的单位费用
path.push_back(d[t]);
maxflow += incf[t];
res += d[t] * incf[t];
}
int main()
{
while (scanf("%d%d", &n, &m) != EOF)
{
memset(h, -1, sizeof h), idx = 0;
path.clear();
s = 1, t = n;
int a, b, c;
for (int i = 1; i <= m; ++i)
{
scanf("%d%d%d", &a, &b, &c);
add(a, b, 1, c);
}
while (spfa()) update();
int sz = path.size();
//增广路费用的前缀和
for (int i = 1; i <= sz; ++i)
{
sum[i] = sum[i - 1] + path[i - 1];
}
int q;
scanf("%d", &q);
while (q--)
{
LL u, v;
scanf("%lld%lld", &u, &v);
if (u * sz < v)
puts("NaN");
else
{
LL a = v / u;
LL b = v % u;
LL ans;
if (b == 0)
ans = sum[a] * u;
else
ans = sum[a] * u + path[a] * b;
LL down = gcd(ans, v);
ans /= down;
v /= down;
printf("%lld/%lld
", ans, v);
}
}
}
return 0;
}
J.Easy Integration(找规律)
题目链接:https://ac.nowcoder.com/acm/contest/5666/J
n = 1时, res = 1 / (2 * 3)
n = 2时, res = (1 * 2) / (3 * 4 * 5)
n = 3时, res = (1 * 2 * 3) / (4 * 5 * 6 * 7)
(res = frac{n!}{frac{(2 * n + 1)!}{n!}})
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
using LL = long long;
const int mod = 998244353;
const int N = 2000005;
int fact[N], infact[N];
int qmi(int a, int k, int p)
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int main()
{
fact[0] = infact[0] = 1;
for (int i = 1; i < N; ++i)
{
fact[i] = (LL)fact[i - 1] * i % mod;
infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
}
int n;
while (cin >> n)
{
//int up = n;
int down = 2 * (n + 1);
int res = 1;
res = (LL)res * fact[n] % mod;
res = (LL)res * res % mod;
res = (LL)res * 2 * (n + 1) % mod;
cout << (LL)res * infact[down] % mod << endl;
}
return 0;
}