A
题意: n个数,两两配对,要求配对后的和相等。保证存在方案。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 1e6 + 1;
const int MAXM = 1e5 + 1;
const int INF = 1e9 + 10;
int a[110];
vector<int> G[110];
bool vis[110];
int main()
{
int n;
while(scanf("%d", &n) != EOF) {
int sum = 0;
for(int i = 1; i <= 100; i++) {
G[i].clear(); vis[i] = false;
}
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum += a[i];
G[a[i]].push_back(i);
}
int ave = 2 * sum / n;
for(int i = 1; i <= n; i++) {
if(vis[i]) continue;
vis[i] = true;
int val = ave - a[i];
for(int j = 0; j < G[val].size(); j++) {
int id = G[val][j];
if(vis[id]) continue;
else {
printf("%d %d\n", i, id);
vis[id] = true;
break;
}
}
}
}
return 0;
}
B
题意:n * n的格子,位置(i,j)的士兵可以攻击到第i行和第j列的所有位置。现在要放m个士兵,问你前i个士兵不能攻击到的位置总数。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 1;
const int MAXM = 1e6 + 1;
const int INF = 1e9 + 10;
bool row[MAXN], cul[MAXN];
LL ans[MAXN];
int main()
{
int n, m;
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = 1; i <= n; i++) {
row[i] = cul[i] = false;
}
LL num = 1LL * n * n;
int nrow = 0, ncul = 0;
for(int i = 1; i <= m; i++) {
int x, y; scanf("%d%d", &x, &y);
if(!row[x]) {
num = num - n + ncul;
}
if(!cul[y]) {
num = num - n + nrow;
}
if(!row[x] && !cul[y]) {
num++;
nrow++; ncul++;
row[x] = true;
cul[y] = true;
}
else if(!row[x]) {
nrow++;
row[x] = true;
}
else if(!cul[y]) {
ncul++;
cul[y] = true;
}
ans[i] = num;
}
for(int i = 1; i <= m; i++) {
if(i > 1) printf(" ");
printf("%lld", ans[i]);
}
printf("\n");
}
return 0;
}
题意:给定一个字符串,问你最短的子串覆盖出现的所有字符。
尺取 or 二分
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 1;
const int MAXM = 1e6 + 1;
const int INF = 1e9 + 10;
char str[MAXN];
int sum1[MAXN][30], sum2[MAXN][30];
bool vis1[30], vis2[30];
bool Check(int L, int R) {
for(int i = 0; i <= 25; i++) {
if(vis1[i]) {
if(sum1[R][i] - sum1[L-1][i] < 1) return false;
}
if(vis2[i]) {
if(sum2[R][i] - sum2[L-1][i] < 1) return false;
}
}
return true;
}
int n;
bool judge(int o) {
for(int i = 1; i + o - 1 <= n; i++) {
if(Check(i, i + o - 1)) return true;
}
return false;
}
int main()
{
while(scanf("%d", &n) != EOF) {
scanf("%s", str + 1);
for(int i = 0; i <= 25; i++) {
sum1[0][i] = sum2[0][i] = 0;
vis1[i] = vis2[i] = false;
}
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= 25; j++) {
sum1[i][j] = sum1[i-1][j];
sum2[i][j] = sum2[i-1][j];
}
if(str[i] >= 'a' && str[i] <= 'z') {
int v = str[i] - 'a';
sum1[i][v]++;
vis1[v] = true;
}
else {
int v = str[i] - 'A';
sum2[i][v]++;
vis2[v] = true;
}
}
int l = 1, r = n, ans;
while(r >= l) {
int mid = (l + r) >> 1;
if(judge(mid)) {
ans = mid;
r = mid - 1;
}
else {
l = mid + 1;
}
}
printf("%d\n", ans);
}
return 0;
}
题意:n个人从0位置到L位置,步行速度v1,乘车速度v2。每趟车只能载k个人,每个人只能坐一次车,问所有人到达L位置的最短时间。
思路:YY最优情况下,每个人步行、乘车距离是相等的。
发现每个上车点到下一个上车点的距离是一定的,这样我们依次求出每个上车位置。
设最后一个上车位置为d,d就是步行距离,乘车距离 = L - d。
然后时间 = d / v1 + (L - d) / v2。
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <string>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 1e5 + 10;
const int MAXM = 1e5 + 1;
const int INF = 1e9 + 10;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) {x += y; x %= MOD;}
int main()
{
int n, l, v1, v2, k;
while(scanf("%d%d%d%d%d", &n, &l, &v1, &v2, &k) != EOF) {
int m = n % k == 0 ? n / k : n / k + 1;
double l1 = (2.0 * (m - 1) * l * v1) / ((v2 - v1) * 1.0 + 2.0 * m * v1);
double l2 = l * 1.0 - l1;
printf("%.10lf\n", l1 / v1 + l2 / v2);
}
return 0;
}
题意:给定一棵树和k对点,问你这k对点两两匹配后各自距离之和的最大值。
思路:因为是一棵树,把这k对点连接起来的路径是唯一的。也就是说,我们只需要统计这个路径上每条边被覆盖多少次即可。
显然对于第i条边u -> v,若v上面有x个点,下面有y个点,这些点两两匹配的缘故这条边肯定要被覆盖min(x, y)次,因此我们只需要DFS一次统计贡献就好了。
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstring>
#include <queue>
#include <map>
#include <set>
#include <string>
#define CLR(a, b) memset(a, (b), sizeof(a))
#define ll o<<1
#define rr o<<1|1
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
const int MAXN = 2 * 1e5 + 10;
const int MAXM = 1e5 + 1;
const int INF = 1e9 + 10;
const int MOD = 1e9 + 7;
void add(LL &x, LL y) {x += y; x %= MOD;}
int n, k;
LL ans;
vector<int> G[MAXN];
int num[MAXN];
void DFS(int u, int fa) {
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(v == fa) continue;
DFS(v, u);
num[u] += num[v];
ans += min(num[v], k - num[v]);
}
}
int main()
{
while(scanf("%d%d", &n, &k) != EOF) {
k <<= 1;
for(int i = 1; i <= n; i++) num[i] = 0, G[i].clear();
for(int i = 1; i <= k; i++) {
int u; scanf("%d", &u);
num[u] = 1;
}
for(int i = 0; i < n - 1; i++) {
int u, v; scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
ans = 0; DFS(1, -1);
printf("%lld\n", ans);
}
return 0;
}