链接
A. Adrien and Austin
题意:
给定n个石头,每次可以取走连续的长度不超过K的连续石头,若无法进行操作即失败。
博弈论,若先手能将序列变成对称的两部分则必胜,否则必败。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, k;
cin >> n >> k;
if(k != 1){
if(n) cout << "Adrien\n";
else cout << "Austin\n";
}
else{
if(n & 1) cout << "Adrien\n";
else cout << "Austin\n";
}
return 0;
}
D. Country Meow
题意:
给定n个点的三维点集,求出该点集的最小球覆盖。
,,可以使用三分套三分套三分的方法来求解。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1e5 + 10;
struct point {
double x, y, z;
}p[maxn];
const double eps = 1e-10;
int n;
double dist(point x, point y)
{
return sqrt((x.x - y.x) * (x.x - y.x) + (x.y - y.y) * (x.y - y.y) + (x.z - y.z) * (x.z - y.z));
}
double cal(double x, double y, double z)
{
double ans = 0;
for ( int i = 1;i <= n;i++ ) {
ans = max(ans, dist(point({ x,y,z }), p[i]));
}
return ans;
}
double solvez(double x, double y)
{
double ans = 1e12;
double l = -maxn, r = maxn;
while ( r - l > eps ) {
double lmid = l + (r - l) / 3;
double rmid = r - (r - l) / 3;
double temp1 = cal(x, y, lmid);
double temp2 = cal(x, y, rmid);
ans = min(ans, min(temp1, temp2));
if ( temp1 < temp2 ) {
r = rmid;
}
else l = lmid;
}
return ans;
}
double solvey(double x)
{
double ans = 1e12;
double l = -maxn, r = maxn;
while ( r - l > eps ) {
double lmid = l + (r - l) / 3;
double rmid = r - (r - l) / 3;
double temp1 = solvez(x, lmid);
double temp2 = solvez(x, rmid);
ans = min(ans, min(temp1, temp2));
if ( temp1 < temp2 ) {
r = rmid;
}
else l = lmid;
}
return ans;
}
double solvex()
{
double ans = 1e12;
double l = -maxn, r = maxn;
while ( r - l > eps ) {
double lmid = l + (r - l) / 3;
double rmid = r - (r - l) / 3;
double temp1 = solvey(lmid);
double temp2 = solvey(rmid);
ans = min(ans, min(temp1, temp2));
if ( temp1 < temp2 ) {
r = rmid;
}
else l = lmid;
}
return ans;
}
int main()
{
scanf("%d", &n);
for ( int i = 1;i <= n;i++ ) {
scanf("%lf%lf%lf", &p[i].x, &p[i].y, &p[i].z);
}
printf("%.12f\n", solvex());
return 0;
}
G. Pyramid
题意:
给定一个图中的n层的三角形,求出可以构成正三角形的三元点对个数。
找规律可得,直接算即可。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 1e5+10;
const int p = 1e9+7;
typedef long long ll;
int n;
ll ksm(ll x,ll y)
{
ll ret = 1;
do{
if(y & 1)
ret = ret * x % p;
x = x * x % p;
}while(y >>= 1);
return ret;
}
int main()
{
int _;
scanf("%d",&_);
while(_--){
scanf("%d",&n);
ll ans = 1ll * n * (n + 1) % p * (n + 2) % p * (n + 3) % p * ksm(24,p - 2) % p;
printf("%lld\n",ans);
}
return 0;
}
I. Magic Potion
题意:
有n个勇士和m个怪物,每个勇士有一个可击杀的列表,每个英雄只可选择一个可击杀的怪物进行击杀,有k瓶药,每个勇士最多和一瓶,可以额外击杀一只怪物,求可击杀怪物的最大数量。
很明显的一个二分图匹配问题,对于勇士进行拆点,拆成没喝药的和喝了药的。然后建边跑个网络流即可。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 3e5+10;
const int maxm = 1e5+10;
struct Edge{
int val, to, next;
}e[maxm << 1];
int head[maxn], tot = 1;
int cur[maxn];
int k,num,temp;
int dep[maxn];
int n,m;
int s,t;
void addedge(int u,int v,int w)
{
e[++tot]=Edge({w,v,head[u]});
head[u] = tot;
e[++tot]=Edge({0,u,head[v]});
head[v] = tot;
}
int bfs()
{
for(int i = 1;i<=n;i++){
dep[i] = 0;
cur[i] = head[i];
}
// memset(dep,0,sizeof dep);
// memcpy(cur,head,sizeof head);
queue<int> qq;
qq.push(s);
dep[s] = 1;
while(!qq.empty()){
int temp = qq.front();
qq.pop();
for(int i = head[temp];~i;i=e[i].next){
int to = e[i].to;
if(e[i].val && !dep[to]){
dep[to] = dep[temp] + 1;
if(to == t){
return 1;
}
qq.push(to);
}
}
}
return 0;
}
int dfs(int beg,int flow)
{
if(beg == t){
return flow;
}
int ret = 0;
for(int &i = cur[beg];~i;i=e[i].next){
int to = e[i].to;
if(e[i].val && dep[to] == dep[beg] + 1){
int res = dfs(to,min(e[i].val,flow));
ret += res;
e[i].val -= res;
e[i^1].val += res;
if((flow-=ret) <= 0)
break;
}
}
if(ret == 0)
dep[beg] = 0;
return ret;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
memset(head,-1,sizeof head);
for(int i = 1;i<=n;i++){
scanf("%d",&num);
for(int j = 1;j<=num;j++){
scanf("%d",&temp);
addedge(i,2 * n + temp,1);
addedge(n + i,2 * n + temp,1);
}
}
s = 2 * n + 2 * m + 1;
int s1 = s + 1, s2 = s + 2;
t = s + 3;
for(int i = 1;i <= m;i++){
addedge(2 * n + m + i,t,1);
addedge(2 * n + i , 2 * n + m + i, 1);
}
addedge(s,s1,n);
addedge(s,s2,k);
for(int i = 1;i<=n;i++){
addedge(s1,i,1);
addedge(s2,n + i,1);
}
n = 2 * n + 2 * m + 4;
int ans = 0;
while(bfs()){
ans += dfs(s,0x3f3f3f3f);
}
printf("%d",ans);
return 0;
}
J. Prime Game
题意:
给定n个数的序列,求所有子段内的乘积的不同质因子个数和。
共有个子段,考虑计算每个质数的贡献。用埃氏筛预处理出每个质数的倍数出现的位置,然后枚举质数将没有贡献的区间数减去即可。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 2e6 + 10;
typedef long long ll;
#define int ll
vector<int> pos[maxn];
int flag[maxn];
int p[maxn];
vector<int> pp[maxn];
int prime[maxn];
int n, a[maxn];
void pre()
{
p[1] = 1;
for (int i = 2; i < maxn; i++)
{
if (!p[i])
{
prime[++prime[0]] = i;
pos[i].push_back(0);
if (flag[i])
{
for (int j = 0; j < (int)pp[i].size(); j++)
{
pos[i].push_back(pp[i][j]);
}
}
int j = 2 * i;
while (j < maxn)
{
p[j] = 1;
if (flag[j])
{
for (int k = 0; k < (int)pp[j].size(); k++)
{
pos[i].push_back(pp[j][k]);
}
}
j += i;
}
pos[i].push_back(n + 1);
}
}
}
signed main()
{
scanf("%lld", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
flag[a[i]] = 1;
pp[a[i]].push_back(i);
}
pre();
ll tt = 0;
for (int i = 1; i <= prime[0]; i++)
{
int temp = prime[i];
ll ans = n * (n + 1) / 2;
if (pos[temp].size() == 2)
{
continue;
}
sort(pos[temp].begin(), pos[temp].end());
for (int j = 1; j < (int)pos[temp].size(); j++)
{
ll temp1 = pos[temp][j];
ll temp2 = pos[temp][j - 1];
ans -= (temp1 - temp2) * (temp1 - temp2 - 1) / 2;
}
tt += ans;
}
printf("%lld\n", tt);
return 0;
}
K. Kangaroo Puzzle
题意:
给定一个网格图和若干只袋鼠,每次可使所有袋鼠向同一个方向移动一格,求出一个序列使得按照这个序列进行操作后,所有袋鼠都在同一格。
据说正解是搜索,我们用随机水过去的。位置不同的袋鼠数一定是单调不减的,网格图最大只有20*20,输出序列长度可达50000,直接随机输出即可。
#include<bits/stdc++.h>
using namespace std;
char str[100][10000];
int a,b,c,d,e;
int main()
{
cin>>a>>b;
for(int i=1; i<=a; i++)
{
cin>>str[i];
}
for(int i=1; i<=49999; i++)
{
int p=rand()%4;
if(p==0)
cout<<"U";
else if(p==1)
cout<<"D";
else if(p==2)
cout<<"L";
else
cout<<"R";
}
cout<<endl;
return 0;
}