A:博弈
题意:给你 n,k,代表有 n 块石头,每次每个人只能在任意位置拿连续的 1 - k 块石头,轮到谁无石头可拿时谁输。先手赢输出“Adrien”,后手赢输出“Austin”
思路:
- 当 k >= n 时先手赢
- 否则,只要 k 大于 1,或者 k == 1 且 n 为奇数时先手赢。
trick: n 可能等于 0,特判。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n, m;
cin >> n >> m;
if(n == 0)
{
cout << "Austin" << endl;
return 0;
}
if(m == 1)
{
if(n % 2 == 0) cout << "Austin" << endl;
else cout << "Adrien" << endl;
}
else
{
cout << "Adrien" << endl;
}
return 0;
}
D:几何板题,求最小球覆盖
2018 ACM-ICPC 南京站 D Country Meow
E:
xb的代码
#include <bits/stdc++.h>
typedef long long ll;
const int maxn = 1e6 + 5;
using namespace std;
char s[maxn], str[maxn];
int n, k;
string judge(char* t)
{
int m[maxn][2];
int pos = 0;
m[0][0] = -1;
for(int i = 1; i <= n; i++) {
m[++pos][0] = t[i] - '0';
if(m[pos - 1][0] == t[i] - '0') m[pos][1] = m[pos - 1][1] + 1;
else m[pos][1] = 1;
if(m[pos][1] == k) pos -=k;
}
string ans;
for(int i = 1; i <= n; i++) {
if(i <= pos) ans += m[i][0] + '0';
else ans += '0';
}
return ans;
}
int main()
{
cin >> n >> k;
scanf("%s", s + 1);
scanf("%s", str + 1);
string a, b;
a = judge(s);
b = judge(str);
if(a == b) puts("Yes");
else puts("No");
return 0;
}
G:打表找规律
题意:
给你这种三角形塔的层数,问你有多少正三角形,答案模 1e9 + 7
思路:
- gxj自己手动打表前5项发现,对于 n 层的三角形塔来说,它可以形成 n * (n + 1) * (n + 2) * (n + 3) / 24 个正三角形,但是不确定,然后敲了一发过了······tql,%%%
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
int main()
{
ll inv = 41666667;//24 在 1e9 + 7 下的逆元
ll t, n;
scanf("%lld", &t);
while(t--)
{
scanf("%lld", &n);
ll tmp = 1;
for(int i = 0; i < 4; i++)
{
tmp *= (n + i);
tmp %= mod;
}
tmp *= inv;
tmp %= mod;
printf("%lld\n", tmp);
}
return 0;
}
I:二分图 or 最大流
题意: n 个英雄,m 个怪兽,再给你每个英雄可以攻击的怪兽编号,每个英雄只能攻击可攻击的一个怪兽,一个怪兽只能被攻击一次,然后有 k 瓶药,给英雄使用药之后英雄可以额外攻击一个可攻击的怪兽,一个英雄只能用一瓶药,一瓶药只能对一个英雄使用。问你最多可以攻击多少怪兽。
思路:
- 二分图匹配,首先对于每一个英雄建图的时候建一个英雄的复制,然后先对前 n 个英雄跑一遍二分图匹配,然后被匹配的英雄次数加一,之后对后 n 个英雄的复制跑一遍匹配,同时计次数,次数大于 1 表示不可匹配
- 最大流,额外建一个源点,一个汇点,一个 k 点,代表 k 瓶药,然后建边,首先源点与 k 点建一条权值为 k 的边,之后对于每一个英雄,源点与英雄之间建一条权值为一的边,k 点与英雄之间建一条权值为一的边,英雄与他可攻击的怪兽之间建一条权值为一的边,每只怪兽与汇点之间建一条权值为一的边,要注意每只可攻击的怪兽与汇点之间只能建一条边。跑一边最大流就是答案。
#include<bits/stdc++.h>//二分图匹配
using namespace std;
typedef long long ll;
const int N = 510;
int n, m, k;
int num[2 * N];
int from[2 * N], tot;
bool use[N];
vector<int> g[2 * N];
bool match(int x)
{
if(num[x] >= 2) return false;//加一个限制
int len = g[x].size();
for(int i = 0; i < len; i++)
{
if(!use[g[x][i]])
{
use[g[x][i]] = true;
if(from[g[x][i]] == -1 || match(from[g[x][i]]))
{
from[g[x][i]] = x;
return true;
}
}
}
return false;
}
int hungary(int x)
{
tot = 0;
for(int i = 1; i <= n; i++)
{
memset(use, 0, sizeof(use));
if(match(i + x))
{
tot++;
num[i + x]++;
}
}
return tot;
}
int main()
{
memset(from, -1, sizeof(from));
int x, y;
scanf("%d %d %d", &n, &m, &k);
for(int i = 1; i <= n; i++)
{
scanf("%d", &x);
for(int j = 0; j < x; j++)
{
scanf("%d", &y);
g[i].push_back(y);
g[i + n].push_back(y);
}
}
int ans = hungary(0);
int sum = hungary(n);
printf("%d\n", min(ans + sum, ans + k));
return 0;
}
#include<bits/stdc++.h>//最大流
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 2010;
struct node
{
int to, c, next;
} edge[1000010];
int tot;
int head[N];
int level[N];
void add(int u, int v, int w)
{
edge[tot].c = w;
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
edge[tot].c = 0;
edge[tot].to = u;
edge[tot].next = head[v];
head[v] = tot++;
}
int bfs(int s, int d)
{
memset(level, -1, sizeof(level));
level[s] = 0;
queue<int> q;
q.push(s);
while(q.size())
{
int u = q.front();
if(u == d) return 1;
q.pop();
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
int c = edge[i].c;
if(level[v] == -1 && c)
{
level[v] = level[u]+1;
q.push(v);
}
}
}
return 0;
}
int dfs(int u, int d, int f)
{
if(u == d) return f;
int t = 0;
int tmp;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
int c = edge[i].c;
if(c && level[v] == level[u]+1 && (tmp = dfs(v, d, min(f, c))))
{
edge[i].c -= tmp;
edge[i^1].c += tmp;
t += tmp;
f -= tmp;
if(!f) break;
}
}
if(t) return t;
level[u] = -1;
return 0;
}
int dinic(int s, int d)
{
int ans = 0;
while(bfs(s, d))
{
int tmp = dfs(s, d, inf);
if(!tmp) break;
ans += tmp;
}
return ans;
}
int vis[N];
int main()
{
tot = 0;
memset(head, -1, sizeof(head));
int m, n, k;
int x, y;
int s = 0, t = 1100, kk = 1050;
scanf("%d %d %d", &n, &m, &k);
add(s, kk, k);//s -> k
for(int i = 1; i <= n; i++)
{
add(s, i, 1);//s -> hero
add(kk, i, 1);//k -> hero
scanf("%d", &x);
for(int j = 0; j < x; j++)
{
scanf("%d", &y);
add(i, y + n, 1);//hero -> monster
if(!vis[y]) add(y + n, t, 1);//monster -> d
vis[y]++;
}
}
int ans = dinic(s, t);
printf("%d\n", ans);
return 0;
}
J:素数筛 + 因子贡献度
题意:
思路:【ACM-ICPC 2018 南京现场赛 】 J.Prime Game ---- 思维+素数筛
我觉得没有必要开二维的数组,我们可以直接在筛素数的时候直接把所有数的素因子直接放进 vector 里面,然后开一个 pre 数组,pre [ i ] 表示 i 这个素数上一次出现是在哪个位置。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 1000010;
int n, x;
bool is_pri[N];
int pre[N];
vector<int> ve[N];
void get_pri()
{
is_pri[1] = is_pri[0] = true;
for(int i = 2; i < N; i++)
{
if(!is_pri[i])
{
ve[i].push_back(i);
for(int j = i + i; j < N; j += i)
{
is_pri[j] = true;
ve[j].push_back(i);
}
}
}
}
int main()
{
get_pri();
ll ans = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &x);
int len = ve[x].size();
for(int j = 0; j < len; j++)
{
ans += (ll)((ll)(i - pre[ve[x][j]]) * (ll)(n - i + 1));
pre[ve[x][j]] = i;
}
}
printf("%lld\n", ans);
return 0;
}
K:玄学
题意:给你一个 n * m 的 0 1 矩阵,1 代表该位置有一个袋鼠,0 代表障碍物,你可以进行上下左右四种操作,每次操作所有袋鼠一起动,如果动的方向有障碍物,那么不动,让你输出50000长度以内的字符串,使得所有袋鼠走到一起。
思路:
- 敲了一发50000的随机,过了······
- 网上的代码有思维 + 构造······
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n,m;
char mmp[25];
char ppp[]={"DLUR"};
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%s",mmp);
for(int i=0;i<50000;i++)
{
int j=rand();
printf("%c",ppp[j%4]);
}
}