2016-2017 ACM-ICPC East Central North America(ECNA 2016)【solved :7 / 10】

题目链接:http://codeforces.com/gym/101196

小结:BCE题没啥好说的,F是dp,有可取之处。G是一道思维题(但是还没有全懂qls的思路)。I题是一个简单最大流。D是一个简单bfs吧(还没写对)。H好像是个瞎搞题,没写。
updata:2018年5月28日22:25:47

B - Foosball Dynasty (模拟)

思路:依照题意模拟即可

#include <bits/stdc++.h>
using namespace std;
string name[10 + 5];

int main()
{
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        cin >> name[i];
    }

    int wwin = 0, bwin = 0;
    string wo = name[0], bo = name[1], wd = name[2], bd = name[3];
    string wfirst = name[0], wsecond = name[2], bfirst = name[1], bsecond = name[3];
    queue<string>que;
    for(int i = 4; i < n; i++)  que.push(name[i]);

    string str;
    cin >> str;
    int ans = 0;
    vector<pair<string, string>>vec;
    for(int i = 0; i < str.size(); i++)
    {
        if(str[i] == 'W')
        {// white win
            swap(wd, wo);

            que.push(bd);
            bd = bo;
            bo = que.front();que.pop();
            bfirst = bd;
            bsecond = bo;

            wwin++;
            bwin = 0;
            if(wwin > ans)
            {
                ans = wwin;
                vec.clear();
                vec.push_back({wfirst, wsecond});
            }
            else if(wwin == ans) vec.push_back({wfirst, wsecond});
        }
        else
        {//black win
            swap(bd, bo);

            que.push(wd);
            wd = wo;
            wo = que.front();que.pop();
            wfirst = wd;
            wsecond = wo;

            bwin++;
            wwin = 0;
            if(bwin > ans)
            {
                ans = bwin;
                vec.clear();
                vec.push_back({bfirst, bsecond});
            }
            else if(bwin == ans)    vec.push_back({bfirst, bsecond});
        }
    }

    for(auto o : vec)   cout << o.first << " " << o.second <<endl;
    return 0;
}

C - The Key to Cryptography(water)

#include <bits/stdc++.h>
using namespace std;

int main()
{
    string cip, key;
    cin >> cip >> key;
    string plain = "";
    for(int i = 0; i < cip.size(); i++)
    {
        int off = key[i] - 'A';
        char temp = (cip[i] - 'A' + 26 - off) % 26 + 'A';
        plain += temp, key += temp;
    }
    cout << plain << endl;
    return 0;
}

D - Lost in Translation

E - Red Rover(暴力)

给出一个字符串 ( l e n 100 ) ,若能把其中一个子串作为marco串,把原串缩成若干marco串和其他字符,总长度将变成marco串数量+其他字符的总数量。问这个原串的最小总长度是多少。

思路:枚举每一个子串作为marco串,对原串检查即可。

#include <bits/stdc++.h>
using namespace std;

string s;
bool judge(int idx, int st, int ed)
{
    for(int i = idx ; i < idx + (ed - st + 1); i++)
    {
        if(s[i] != s[st + i - idx]) return false;
    }
    return true;
}
int main()
{
    cin >> s;

    int minn = s.size();
    for(int st = 0; st < s.size(); st++)
    {
        for(int ed = st; ed < s.size(); ed++)
        {
            int idx = 0, cnt = 0;
            while(idx < s.size())
            {
                if(judge(idx, st, ed))  idx = idx + (ed - st + 1), cnt++;
                else idx++;
            }
            minn = min(minn, (int)s.size() - cnt * (ed - st + 1 - 1) + ed - st + 1);
        }
    }
    printf("%d\n", minn);
    return 0;
}

F - Removal Game (dp)

题意:给出一个序列 ( l e n 100 , a [ i ] 1 e 3 ) ,每次选择一个a[k]删除,这个操作的花费是它左边第一个,右边第一个,两个未删除的元素的gcd。整个数组可看做一个环,即最初未删除任何元素时,a[n-1]的右边第一个数字为a[0]。

思路:dp[i][j]:a[i]到a[j]之间只剩下a[i]和a[j]的最小花费。最后的答案显然是 min d p [ i ] [ j ] + d p [ j ] [ i ] + g c d ( a [ i ] , a [ j ] ) ,因为题意是一个环,所以可以从a[j]再绕到a[i]。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 5;
const int INF = 0x3f3f3f3f;
int a[maxn];
int dp[maxn][maxn];

int main()
{
    int n;
    while(~scanf("%d", &n))
    {
        if(n == 0)  break;
        for(int i = 0; i < n; i++)  scanf("%d", &a[i]);

        memset(dp, INF, sizeof(dp));
        for(int len = 2; len <= n; len++)
        {
            for(int st = 0, ed = len - 1; st < n; st++, ed = (ed + 1) % n)
            {
                if(len == 2)
                {
                    dp[st][ed] = 0;
                }
                else for(int k = (st + 1) % n; k != ed; k = (k + 1) % n)
                     {
                         dp[st][ed] = min(dp[st][ed], dp[st][k] + dp[k][ed] + __gcd(a[st], a[ed]));
                     }
            }
        }
        int ans = INF;
        for(int i = 0; i < n; i++)
            for(int j = i + 1; j < n; j++)
                ans = min(ans, dp[i][j] + dp[j][i] + __gcd(a[i], a[j]));
        printf("%d\n", ans);
    }
    return 0;
}

G - That’s One Hanoi-ed Teacher (思维)

给出汉诺塔三个塔的状态, ( n 50 ) ,问,这是否是汉诺塔的最佳步骤中的一步,若是则输出还要几步才能完成。

#include <bits/stdc++.h>
using namespace std;

vector<int>vec[3];
int ok = 1;
long long ans = 0;
void dfs(int lv, vector<int> &a, vector<int> &b, vector<int> &c)
{
    if(lv == 0) return ;
//    printf("lv = %d\n", lv);
//    printf("a :");for(auto o : a) cout << o << " ";puts("");
//    printf("b :");for(auto o : b) cout << o << " ";puts("");
//    printf("c :");for(auto o : c) cout << o << " ";puts("");
    int judge1 = (a.size() != 0 && a[0] == lv);
    int judge2 = (c.size() != 0 && c[0] == lv);

    if(judge1 == 0 && judge2 == 0)  ok = 0;
    if(ok == 0) return ;

    if(judge1)
    {
        ans += (1LL << (lv-1));
        a.erase(a.begin());
        dfs(lv-1, a, c, b);
    }
    else if(judge2)
    {
        c.erase(c.begin());
        dfs(lv-1, b, a, c);
    }
}
int main()
{
    for(int k = 0; k < 3; k++)
    {
        int n;
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
        {
            int x;
            scanf("%d", &x);
            vec[k].push_back(x);
        }
    }
    dfs(vec[0].size()+vec[1].size()+vec[2].size(), vec[0], vec[1], vec[2]);
    if(ok)  printf("%lld\n", ans);
    else puts("No");

    return 0;
}

I - Waif Until Dark (网络流)

你有n个孩子,每个孩子有k个喜欢的玩具,一共有p个种类的玩具(但是有可能有玩具不属于这p类,意味着他们集成一个第p+1类)。告诉你每个孩子喜欢的k个玩具是什么,告诉你每个种类的玩具有哪些。再告诉你每个种类的玩具最多能有几个可以拿来给孩子玩。问你最多能使得多少个孩子能玩上他喜欢的玩具。

思路:最大流建图。超级源点向孩子连边,容量为1,代表每个孩子只能选一个玩具,每个孩子向自己喜欢的玩具连边,容量为1,代表每个孩子只能选一个玩具,玩具向自己的所属种类连边,容量为1,代表每个玩具贡献度为1,每个种类向超级汇点连边,容量为该种类能使用的最大数量,代表这个种类的最大贡献度。

#include <bits/stdc++.h>
using namespace std;

const int maxv = 1000 + 6;
const int INF = 0x3f3f3f3f;
struct Edge{int from, to, cap, flow;};
struct Dinic
{
   int vs, st, ed;//st源点编号,ed汇点编号


   vector<Edge>edges;
   vector<int>G[maxv];//G[i][j]:节点i的第j条边在edges数组里的序号
   bool vis[maxv];
   int d[maxv];
   int cur[maxv];//当前弧的下标

   void addedge(int from, int to, int cap)
   {
       edges.push_back({from, to, cap, 0});
       edges.push_back({to, from, 0, 0});
       int m = edges.size();
       G[from].push_back(m-2);
       G[to].push_back(m-1);
   }

   bool bfs()
   {
       memset(vis, 0, sizeof(vis));
       queue<int>que;
       que.push(st);
       d[st] = 0;
       vis[st] = 1;
       while(que.size())
       {
           int u = que.front();que.pop();
           for(auto o : G[u])
           {
               Edge &e = edges[o];
               if(!vis[e.to] && e.cap > e.flow)
               {
                   vis[e.to] = 1;
                   d[e.to] = d[u] + 1;
                   que.push(e.to);
               }
           }

       }
       return vis[ed];
   }

   int dfs(int x, int a)//当前节点x。当前所有弧的最小残量a
   {//保存每个节点x正在考虑的弧cur[x];
       if(x == ed ||a == 0)  return a;
       int flow = 0, f;
       for(int &i = cur[x]; i < G[x].size(); i++)
       {
           int idx = G[x][i];
           Edge &e = edges[idx];
           if(d[x] + 1 == d[e.to])
           {
               int f = dfs(e.to, min(a, e.cap - e.flow));
               if(f > 0)
               {
                   e.flow += f;
                   edges[idx^1].flow -= f;
                   flow += f;
                   a -= f;
                   if(a == 0)   break;
               }
           }
       }
       return flow;
   }


   int maxFlow(int s, int t)
   {
       st = s, ed = t;
       int flow = 0;
       while(bfs())
       {
           memset(cur, 0, sizeof(cur));
           flow += dfs(s, INF);
       }
       return flow;
   }
};
int vis[maxv];
int main()
{
    int children, toy, category;
    scanf("%d%d%d", &children, &toy, &category);// 1 2 3 4 5

    Dinic dinic;
    dinic.vs = 1 + children + toy + (category + 1);
    dinic.st = 0, dinic.ed = dinic.vs;

    for(int i = 1; i <= children; i++)
    {
        int k;
        scanf("%d", &k);
        while(k--)
        {
            int x;
            scanf("%d", &x);
            dinic.addedge(i, x + children, 1);
        }
        dinic.addedge(dinic.st, i, 1);
    }

    for(int i = 1; i <= category; i++)
    {
        int l;
        scanf("%d", &l);
        int u = children + toy + i;
        while(l--)
        {
            int x;
            scanf("%d", &x);
            vis[x] = 1;
            dinic.addedge(x + children, u, 1);
        }
        int r;
        scanf("%d", &r);
        dinic.addedge(u, dinic.vs, r);
    }
    vector<int>vec;
    for(int i = 1; i <= toy; i++)
    {
        if(vis[i])  continue;
        vec.push_back(i);
        dinic.addedge(i + children, children + toy + category + 1, 1);
    }
    dinic.addedge(children + toy + category + 1, dinic.ed, vec.size());

    printf("%d\n", dinic.maxFlow(dinic.st, dinic.ed));

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_29556211/article/details/80449770