C - Route Map
题意
:给定n个S串和m个T串,对于每一个S串问是否其出现在T串中。
题解
:map模拟记录T串,对于S,询问map中是否存在就行。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <string>
#include <vector>
#include <map>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
string s[N];
map<string, bool> h;
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
cin >> s[i];
string res;
for (int i = 1; i <= m; i ++ )
{
cin >> res;
h[res] = true;
}
for (int i = 1; i <= n; i ++ )
if (h[s[i]]) puts("Yes");
else puts("No");
return 0;
}
D - Dance (dfs)
题意
:有n个人,并给出两两配对的亲和度,找出所有匹配对的亲和度的异或最大值
题解
:对于每个人,去寻找还未匹配到人的就行,第一个人可匹配的人数为(n - 1),第二个未匹配的人可匹配的人数为(n - 3),依次类推,因此复杂度为O((n - 1) (n - 3) * (n - 5)…*2),n最大是16,因此时间复杂度试2e6左右。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 30;
int g[N][N]; // g[i][j]表示i和j匹配的亲和度
bool st[N]; // 用于标记此人是否匹配了
int ans = 0, n;
// cnt表示这是第几个人,res是当前及匹配的亲和度的异或值
void dfs(int cnt, int res)
{
if (!cnt) // 匹配完
{
ans = max(ans, res);
return;
}
if (st[cnt]) // 这个人已经被匹配了
{
dfs(cnt - 1, res);
return;
}
for (int i = 1; i <= n; i ++ )
{
if (i == cnt || st[i]) continue;
st[cnt] = st[i] = true;
dfs(cnt - 1, res ^ g[cnt][i]);
st[cnt] = st[i] = false; // 回溯,还原现场
}
}
int main()
{
scanf("%d", &n);
n *= 2;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
{
if (j <= i) continue;
scanf("%d", &g[i][j]);
g[j][i] = g[i][j];
}
dfs(n, 0);
printf("%d\n", ans);
return 0;
}
E - Average and Median (二分 + DP)
题意
:给出n 个数a1…an,然后选取一些数出来,选取数的方式是对于每一个 i (1<=i<=n-1), 第i个数或第i+1个数至少选出来一个,问在所有的这些选法中的最大平均值和最大中位数是多少。
题解
:二分答案用dp去check二分出来的值是否合法。
对于求最大的平均值:假设现在二分到的答案是mid,那么我们令b[i] = a[i] - mid,如果按题目给出的选法在b数组中选出的数的和至少有一组大于等于0说明真实答案一定不会比mid小,然后令l = mid, 所以我们只需求出最大的一组和就行。令f[i][0]表示从前i个数里面选且不选i的最大的和,f[i][1]表示从前i个数里面选且选i的最大的和,因此f[i][0] = f[i - 1][1](第i个不选,因此第i - 1个一定要选),f[i][1] = max(f[i - 1][0], f[i - 1][1]) + b[i](第i个选,因此第i - 1个可选可不选,找其中的最大值就行),若max(f[i][0], f[i][1]) >= 0, 说明选出来的方案中至少存在一组数的和大于等于0.
对于求最大的中位数:对于中位数我们可以发现大于等于中位数的数的数量一定是 大于 小于中位数的数的数量(有点拗口 ),所以只要我们能在a[i]中按题目的选法选出大于等于mid的数量 大于 小于mid的数量,说明真实答案一定不会比mid小,然后令l = mid。因此在这里, 如果a[i] >= mid,则令b[i] = 1, 否则令b[i] = -1,所以在b数组中选出一组数的和大于0即可,我们同样是找选出来的和最大值是否大于0即可,dp转移方程如上。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int g[N];
int n;
bool check1(double x)
{
vector<vector<double> > f(n + 1, vector<double>(2));
f[0][0] = 0, f[0][1] = 0;
for (int i = 1; i <= n; i ++ )
{
f[i][0] = f[i - 1][1];
f[i][1] = max(f[i - 1][1], f[i - 1][0]) + g[i] - x;
}
// cout << x << " " << max(f[n][0], f[n][1]) << endl;
return max(f[n][0], f[n][1]) >= 0;
}
bool check2(int x)
{
vector<vector<int> > f(n + 1, vector<int>(2));
for (int i = 1; i <= n; i ++ )
{
f[i][0] = f[i - 1][1];
f[i][1] = max(f[i - 1][1], f[i - 1][0]) + (g[i] >= x ? 1 : -1);
}
return max(f[n][0], f[n][1]) > 0;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &g[i]);
double l = 0, r = 1e9;
while (r - l >= 1e-6)
{
double mid = (l + r) / 2;
if (check1(mid)) l = mid;
else r = mid;
}
int L = 0, R = 1e9;
while (L < R)
{
int mid = L + R + 1 >> 1;
if (check2(mid)) L = mid;
else R = mid - 1;
}
cout << l << "\n" << L << endl;
return 0;
}
完结,如有错误,还请指出,感谢!!!