2018 ICPC南京现场赛

A Adrien and Austin

题目链接
题意:有n块石头,下标从1-n。每个人能够拿[1,k]个数量的连续块。两个人轮流拿,若一个人不能拿则失败。求谁胜利。
思路:先手必败态1、n=0 2、n=1并且n%2==0。当k>=2时,先手可以先拿中间部分,无论后手怎么拿,先手在零一半的地方复制即可保持胜利。

#include <bits/stdc++.h>

using namespace std;

string a="Adrien";
string b="Austin";
int main(){
    int n,k;
    scanf("%d%d",&n,&k);
    if(n==0)
        cout<<b<<endl;
    else if(k>=2)
        cout<<a<<endl;
    else if(n%2==1)
        cout<<a<<endl;
    else
        cout<<b<<endl;
    return 0;
}

D Prime Game

题目链接
题意:未知。
思路:模拟退火。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <math.h>
#include <cstdlib>
#include <algorithm>

#define sqr(x) ((x)*(x))
#define Max(a,b) a>b?a:b
#define Min(a,b) a<b?a:b
#define maxn 106
#define eps 1e-8

using namespace std;
struct cpoint {
    double x, y, z, d;
};

cpoint cp[maxn], rp;
int n;
double dis(cpoint p, cpoint q) {
    return sqrt(sqr(p.x - q.x) + sqr(p.y - q.y) + sqr(p.z - q.z));
}
const int N = 2e5;

void solve() {
    int L = 300, id, ip;
    rp.x = double((rand() % 1000000 + 1) / 1000000.00000 * N);
    rp.y = double((rand() % 1000000 + 1) / 1000000.00000 * N);
    rp.z = double((rand() % 1000000 + 1) / 1000000.00000 * N);
    rp.d = 0.0;
    for (int i = 0; i<n; i++) {
        if (dis(rp, cp[i])>rp.d) {
            rp.d = dis(rp, cp[i]);
            id = i;
        }
    }
    double dal = 100;
    while (dal>eps) {
        for (int i = 0; i<L; i++) {
            rp.x += dal * (cp[id].x - rp.x) / rp.d;
            rp.y += dal * (cp[id].y - rp.y) / rp.d;
            rp.z += dal * (cp[id].z - rp.z) / rp.d;
            rp.d = 0.0;

            for (int j = 0; j<n; j++)
                if (dis(rp, cp[j])>rp.d) {
                    id = j;
                    rp.d = dis(rp, cp[j]);
                }
        }
        dal *= 0.98;
    }
    printf("%.15lf\n", rp.d);
}

int main() {
    while (scanf("%d", &n) != EOF) {
        if (n == 0)break;
        for (int i = 0; i < n; i++) {
            scanf("%lf %lf %lf", &cp[i].x, &cp[i].y, &cp[i].z);
            cp[i].x += 1e5;
            cp[i].y += 1e5;
            cp[i].z += 1e5;
        }
        solve();
    }
}
/*
4
0 0 0
10000 0 0
0 10000 0
0 0 10000
3
0 0 0
3 0 0
0 4 0


*/

/*
8164.96631812619
8164.965809282082773  95
8164.965809399971477  93
8164.966205792577966  94
*/

E Eva and Euro coins

题目链接
题意:给你01字符串s和t,要求s和t最终相同,只有一种操作选择连续k个相同面的硬币翻转。
思路:用栈维护连续的硬币,贪心消去

#include<iostream> 
#include<cstdio>
#include<cstring>
#include<map>
#include<vector> 
#include<set>
#include<queue>
#include<algorithm>
#include<string>
#include<cmath>
#include<stack>
#include<functional>
#include<bitset>
#include<cstdlib>
#include<ctime>
#define ll long long
#define maxn 100002
const int INF = 0x3f3f3f3f;

using namespace std;
char ch1[maxn * 10], ch2[maxn * 10];
vector<int> v1, v2, num;
int main(void){
    int n, k, i, j, flag, s;
    scanf("%d %d",&n,&k);
    scanf("%s %s",ch1,ch2);
    if(k > 1){
        flag = ch1[0];
        num.push_back(1);
        v1.push_back(ch1[0]);
        s = 1;
        for(i = 1;i < n;i++){
            v1.push_back(ch1[i]);
            if(ch1[i] == flag){
                num[s - 1]++;
                if(num[s - 1] == k){
                    for(j = 0;j < k;j++){
                        v1.pop_back();
                    }
                    num.pop_back();
                    s--;
                    if(v1.empty()){
                        flag = 0;
                    }
                    else{
                        flag = '0' + '1' - flag;
                    }
                }
            }
            else{
                flag = ch1[i];
                num.push_back(1);
                s++;
            }
        }
        num.clear();
        flag = ch2[0];
        num.push_back(1);
        v2.push_back(ch2[0]);
        s = 1;
        for(i = 1;i < n;i++){
            v2.push_back(ch2[i]);
            if(ch2[i] == flag){
                num[s - 1]++;
                if(num[s - 1] == k){
                    for(j = 0;j < k;j++){
                        v2.pop_back();
                    }
                    num.pop_back();
                    s--;
                    if(v2.empty()){
                        flag = 0;
                    }
                    else{
                        flag = '0' + '1' - flag;
                    }
                }
            }
            else{
                flag = ch2[i];
                num.push_back(1);
                s++;
            }
        }
        flag = 1;
        s = v1.size();
        if(s == v2.size()){
            for(i = 0;i < s;i++){
                if(v1[i] != v2[i]){
                    flag = 0;
                    break;
                }
            }
        }
        else{
            flag = 0;
        }
        if(flag){
            puts("Yes");
        }
        else{
            puts("No");
        }
    }
    else{
        puts("Yes");
    }
    return 0;
}

G Pyramid

题目链接
题意:由n*(n-1)/2个黑三角形组成大的三角形。求这些黑三角形的顶点选三个可以组成三角形的个数。
思路:寻找三角形构建方式。对于边长为1的三角形个数为1+3+5...通项式n^2。
对于边长大于等于2的三角形个数为1+2+3...通项式n(n-1)/2。对于边长大于等于3的三角形个数,其内部包含的倾斜三角形为其(边长-1)个数。可打表,找出规律C(n,4)。

#include <bits/stdc++.h>

typedef long long ll;
using namespace std;
const int mod=1000000007;

ll n;

ll power_mod(ll a,ll b,ll m){
  ll ans=1;
  a%=m;
  while(b)
  {
    if(b&1)ans=(ans*a)%m;
    a=(a*a)%m;
    b>>=1; 
  }
  return ans;
}//power_mod(b,m-2,m)


int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%lld",&n);
        ll ans=(3+n)*(2+n)%mod*power_mod(4,mod-2,mod)%mod*(1+n)%mod*power_mod(3,mod-2,mod)%mod*n%mod*power_mod(2,mod-2,mod)%mod;
        printf("%lld\n",ans);
    }
}

I Magic Potion

题目链接
题意:n个英雄,m个小怪兽。每个英雄只能杀一个怪兽,有k瓶药,一个英雄只能至多嗑一瓶药,喝了药的英雄能多杀一个怪兽。求最多能杀几个怪兽。
思路:建图跑最大流。超级源点连接两个源点。第一个源点表示没有药普通的图,第二个源点表示k瓶药,拆点给其赋值。

#include <bits/stdc++.h>

#define maxn 505
#define inf 0x3f3f3f3f
using namespace std;

int n, m, k;

struct edge {
    int to, cap, rev;
};

vector <edge>G[maxn << 1];
int level[maxn << 1];
int iter[maxn << 1];

void add_edge(int from, int to, int cap) {
    G[from].push_back({ to, cap, (int)G[to].size() });
    G[to].push_back({ from, 0,(int) G[from].size() - 1 });
}

void bfs(int s) {
    memset(level, -1, sizeof level);
    queue<int>q;
    level[s] = 0;
    q.push(s);
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        for (int i = 0; i<G[v].size(); i++) {
            edge &e = G[v][i];
            if (e.cap>0 && level[e.to]<0) {
                level[e.to] = level[v] + 1;
                q.push(e.to);
            }
        }
    }
}

int dfs(int v, int t, int f) {
    if (v == t)return f;
    for (int &i = iter[v]; i<G[v].size(); i++) {
        edge &e = G[v][i];
        if (e.cap>0 && level[v]<level[e.to]) {
            int d = dfs(e.to, t, min(f, e.cap));
            if (d>0) {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}

int dinic(int s, int t) {
    int flow = 0;
    for (;;) {
        bfs(s);
        if (level[t]<0)return flow;
        memset(iter, 0, sizeof iter);
        int f;
        while ((f = dfs(s, t, inf))>0)
            flow += f;
    }
}

int S, T, SS, Sk1, Sk2;

void input() {
    scanf("%d%d%d", &n, &m, &k);
    int i, j, num, x;
    S = n + m + 1;
    Sk1 = n + m + 2;
    Sk2 = n + m + 3;
    SS = n + m + 4;
    T = n + m + 5;
    add_edge(S, Sk1, inf);
    add_edge(S, SS, inf);
    add_edge(Sk1, Sk2, k);
    for (i = 1; i <= n; i++) {
        add_edge(SS, i, 1);
        add_edge(Sk2, i, 1);
        scanf("%d", &num);
        for (j = 1; j <= num; j++) {
            scanf("%d", &x);
            add_edge(i, n + x, 1);    
        }
    }

    for (i = 1; i <= m; i++)
        add_edge(n + i, T, 1);
}

void solve() {
    printf("%d\n", dinic(S, T));
}

int main() {
    input();
    solve();
}

J Prime Game

题目链接
题意:未知。
思路:计算贡献。

#include<iostream> 
#include<cstdio>
#include<cstring>
#include<map>
#include<vector> 
#include<set>
#include<queue>
#include<algorithm>
#include<string>
#include<cmath>
#include<stack>
#include<functional>
#include<bitset>
#define ll long long
#define maxn 100002
const int INF = 0x3f3f3f3f;

using namespace std;
vector<int> v, vec[maxn];
int prime[maxn * 10], num[maxn * 10];
int vis[maxn*10];
int PP[maxn * 10];

int s;

void init() {
    for (int i = 2; i <= 1000000; i++) {
        if (!vis[i]) {
            prime[s++] = i;
            PP[i] = s - 1;
            for (int j = 2; i * j <= 1000000; j++) {
                vis[i * j] = 1;
            }
        }
    }
}

vector<int>id;

int vv[maxn * 10];

void fun(int x,int Id) {
    for (int i = 0; prime[i] * prime[i] <= x; i++) {
        if (x%prime[i] == 0) {
            while (x%prime[i] == 0) {
                x /= prime[i];
            }
            if (!vv[i]) {
                vv[i] = 1;
                id.push_back(i);
            }
            vec[i].push_back(Id);
        }
        if (x == 1)break;
    }
    if (x!=1) {
        if (!vv[PP[x]]) {
            vv[PP[x]] = 1;
            id.push_back(PP[x]);
        }
        vec[PP[x]].push_back(Id);
    }
}

int main(void) {
    int n;
    ll ans = 0;
    init();
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &num[i]);
        fun(num[i], i);
    }

    for (int i : id) {
        /*printf("%d:    ", i);
        for (int j : vec[i]) {
            printf("%d ", j);
        }
        puts("");
        */
        int sz = vec[i].size();
        for (int j = 0; j < sz; j++) {
            if (j != sz - 1)ans += 1ll * vec[i][j] * (vec[i][j + 1] - vec[i][j]);
            else ans += 1ll * vec[i][j] * (n - vec[i][j] + 1);
        }
    }
    cout << ans << endl;
    return 0;
}

K Kangaroo Puzzle

题目链接
题意:给出n*m的图,图上的1代表有袋鼠,0代表是墙,要求找到一种方案小于50000步,使得最后图上所有合并为同一个袋鼠。
思路:随机4个方向跑随机。

#include<iostream> 
#include<cstdio>
#include<cstring>
#include<map>
#include<vector> 
#include<set>
#include<queue>
#include<algorithm>
#include<string>
#include<cmath>
#include<stack>
#include<functional>
#include<bitset>
#include<cstdlib>
#include<ctime>
#define ll long long
#define maxn 100002
const int INF = 0x3f3f3f3f;

using namespace std;
char ch[22][22];
int main(void){
    srand((int)time(NULL));
    int n, m, i, t;
    scanf("%d %d",&n,&m);
    for(i = 0;i < n;i++){
        scanf("%s",ch[i]);
    }
    for(i = 0;i < 50000;i++){
        t = rand() % 4;
        if(!t){
            printf("U");
        }
        else if(t == 1){
            printf("D");
        }
        else if(t == 2){
            printf("L");
        }
        else if(t == 3){
            printf("R");
        }
    }
    return 0;
}