2018ICPC南京现场赛模拟

A:博弈
题意:给你 n,k,代表有 n 块石头,每次每个人只能在任意位置拿连续的 1 - k 块石头,轮到谁无石头可拿时谁输。先手赢输出“Adrien”,后手赢输出“Austin”

思路:

  1. 当 k >= n 时先手赢
  2. 否则,只要 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

思路:

  1. 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 瓶药,给英雄使用药之后英雄可以额外攻击一个可攻击的怪兽,一个英雄只能用一瓶药,一瓶药只能对一个英雄使用。问你最多可以攻击多少怪兽。

思路:

  1. 二分图匹配,首先对于每一个英雄建图的时候建一个英雄的复制,然后先对前 n 个英雄跑一遍二分图匹配,然后被匹配的英雄次数加一,之后对后 n 个英雄的复制跑一遍匹配,同时计次数,次数大于 1 表示不可匹配
  2. 最大流,额外建一个源点,一个汇点,一个 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长度以内的字符串,使得所有袋鼠走到一起。

思路:

  1. 敲了一发50000的随机,过了······
  2. 网上的代码有思维 + 构造······
#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]);
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值