zoukankan      html  css  js  c++  java
  • ACM International Collegiate Programming Contest, Egyptian Collegiate Programming Contest (ECPC 2015)

    A.Arcade Game(康拓展开)

    题意:

      给出一个每个数位都不同的数n,进行一场游戏。每次游戏将n个数的每个数位重组。如果重组后的数比原来的数大则继续游戏,否则算输。如果重组后的数是最大的数则算赢,问赢的概率。

    题解:

      用康拓展开求出n是第几大的数,然后递推后面的概率。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int t;
    char s[15];
    double ans;
    int fac[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
    double cal(char *s) {
        int res = 0;
        int k = strlen(s);
        for(int i = 0; i < k; i++) {
            int cnt = 0;
            for(int j = i+1; j < k; j++) if(s[j]<s[i]) cnt++;
            res += fac[k-i-1]*cnt;
        } 
        if(res==fac[k]-1) return 0;
        double ans = 1.0/fac[k];
        for(int i = res; i < fac[k]-2; i++) ans += ans/fac[k];
        return ans;
    }
    int main() {
        scanf("%d", &t);
        while(t--) {
            scanf("%s", s);
            printf("%.9lf
    ", cal(s));
        }
    }
    View Code

    B.Unlucky Teacher(模拟)

    题意:

      Q个题目和M个学生的判卷,求出每道题的答案。如果求不出则输出?。

    题解:

      模拟即可。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int t;
    int q, m;
    int num[105], state[105];
    char ans[105];
    char s1[2], s2[2];
    int main() {
        scanf("%d", &t);
        while(t--) {
            memset(state, 0, sizeof(state));
            memset(num, 0, sizeof(num));
            scanf("%d%d", &q, &m);
            while(m--) {
                for(int i = 1; i <= q; i++) {
                    scanf("%s%s", s1, s2);
                    if(s2[0]=='T') num[i] = -1, ans[i] = s1[0];
                    else {
                        if((num[i]==-1)||((state[i]&(1<<s1[0]-'A'))>0)) continue;
                        state[i] |= 1<<s1[0]-'A';
                        num[i]++;
                        if(num[i]==3) {
                            for(int j = 0; j < 4; j++) 
                            if(!(state[i]&(1<<j))) {
                                ans[i] = 'A'+j;
                                break;
                            }
                            num[i] = -1;
                        }        
                    }
                }
            }
            for(int i = 1; i <= q; i++) {
                if(num[i]>-1) printf("?");
                else printf("%c", ans[i]);
                if(i < q) printf(" ");
            }
            puts("");
        }
    }
    View Code

    C.Connecting Graph(并查集+二分)

    题意:

      初始有n个点,m次操作。每次操作加一条边或者询问两个点第一次连通的时刻(若不连通输出-1)。

    题解:

      GYM - 100814 C.Connecting Graph

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5+10;
    int t;
    int n, m;
    int u, v, k;
    int f[N], num[N];
    vector<pair<int, int> > g[N];
    vector<int> c[N];
    bool check(int x) {
        int l = 0, r = g[u].size()-1;
        while(l <= r) {
            int mid = l+r>>1;
            if(g[u][mid].first <= x) l = mid+1;
            else r = mid-1;
        }
        int p1 = g[u][r].second;
        l = 0, r = g[v].size()-1;
        while(l <= r) {
            int mid = l+r>>1;
            if(g[v][mid].first <= x) l = mid+1;
            else r = mid-1;
        }
        int p2 = g[v][r].second;
        if(p1==p2) return 1;
        return 0;
    }
    int main() {
        scanf("%d", &t);
        while(t--) {
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i++) {
                num[i] = 1;
                f[i] = i;
                c[i].clear();
                g[i].clear();
                c[i].push_back(i);
                g[i].push_back(make_pair(0, i));
            }
            for(int i = 1; i <= m; i++) {
                scanf("%d%d%d", &k, &u, &v);
                if(k&1) {
                    u = f[u]; v = f[v];
                    if(u!=v) {
                        if(num[u]>num[v]) swap(u, v);
                        for(int j = 0; j < num[u]; j++) {
                            c[v].push_back(c[u][j]);
                            f[c[u][j]] = v;
                            g[c[u][j]].push_back(make_pair(i, v));
                        }
                        num[v] += num[u];
                        num[u] = 0;
                        c[u].clear();
                    }
                }
                else {
                    int l = 0, r = i-1;
                    while(l<=r) {
                        int mid = l+r>>1;
                        if(check(mid)) r = mid-1;
                        else l = mid+1;
                    }
                    if(check(r+1)) printf("%d
    ", r+1);
                    else puts("-1");
                }
            }
        }    
    }
    View Code

    D.Frozen Rivers

    题意:

      一棵n个节点的树,每条边代表一条河。从点1开始边以每秒1个单位开始融化。每个点连的边(不包括连向父亲的)有一条融化完时剩下的该点连的边融化速度降为0.5。q次询问,每次询问某个时刻融化到叶子节点的数量。

    题解:

      设minn[u]代表节点u的边中权值最小的那个,将点u所有边的权值加上他们与minn[u]的差值。即每条边的权值翻倍再减去minn[u]。

      这样处理完之后就省去了0.5的限制。问题变成了求叶子节点到根节点的距离。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5+10;
    const int inf = 0x3f3f3f3f;
    int t;
    int n, q, p, c;
    int tot;
    int head[N], to[N], nxt[N], w[N], minn[N];
    int cnt;
    ll tim, num[N];
    void dfs(int u, ll val) {
        if(minn[u]==inf) {
            num[++cnt] = val;
            return ;
        }
        for(int i = head[u]; ~i; i = nxt[i]) {
            w[i] = 2*w[i]-minn[u];
            dfs(to[i], val+w[i]);
        }
    }
    int main() {
        scanf("%d", &t);
        while(t--) {
            tot = cnt = 0;
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) head[i] = -1, minn[i] = inf;
            for(int i = 2; i <= n; i++) {
                scanf("%d%d", &p, &c);
                to[++tot] = i; nxt[tot] = head[p]; head[p] = tot, w[tot] = c;
                minn[p] = min(minn[p], c);
            }
            dfs(1, 0);
            sort(num+1, num+cnt+1);
            scanf("%d", &q);
            while(q--) {
                scanf("%lld", &tim);
                int ans = upper_bound(num+1, num+cnt+1, tim)-num-1;
                printf("%d
    ", ans);
            }
        }
    }
    View Code

    E.Palmyra(dp)

    题意:

      给出n*m的矩阵。从点(1,1)出发,可以向右或者向下移动,最后走到(n,m)。将路途上的点值乘起来,问最后的值拿6进制表示末尾最多有几个0。

    题解:

      题意可以理解为,使最后2的因子数和3的因子数中的最小值最大。

      dp[i][j][k]表示走到(i,j),3的因子数为k时2的因子数最多是多少。

    #include <bits/stdc++.h>
    using namespace std;
    int t;
    int n, m;
    int q[105][105][3];
    int dp[105][105][1505];
    int main() {
        scanf("%d", &t);
        while(t--) {
            memset(q, 0, sizeof(q));
            memset(dp, -1, sizeof(dp)); 
            scanf("%d%d", &n, &m);
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= m; j++) {
                    scanf("%d", &q[i][j][0]);
                    int t = q[i][j][0];
                    while(t%2 == 0) {
                        q[i][j][1]++;
                        t /= 2;
                    }
                    while(t%3 == 0) {
                        q[i][j][2]++;
                        t /= 3;
                    }
                }
            }
            dp[1][1][q[1][1][2]] = q[1][1][1];
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= m; j++) {
                    int n2 = q[i][j][1]; 
                    int n3 = q[i][j][2]; 
                    for(int k = 0; k + n3 <= 1500; k++) {
                        if(dp[i][j-1][k] != -1)
                            dp[i][j][k+n3] = max(dp[i][j][k+n3], dp[i][j-1][k]+n2);
                        if(dp[i-1][j][k] != -1)
                            dp[i][j][k+n3] = max(dp[i][j][k+n3], dp[i-1][j][k]+n2);
                    }
                }
            }
            int ans = 0;
            for(int i = 1; i <= 1500; i++) {
                int nn = min(dp[n][m][i], i);
                ans = max(ans, nn);
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code

    F.Geometry

    题意:

      给出长和宽,判断时正方形还是矩形。

    题解:

      判断w是否等于h。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int t;
    int w, h;
    int main() {
        scanf("%d", &t);
        while(t--) {
            scanf("%d%d", &w, &h);
            if(w==h) puts("Square");
            else puts("Rectangle");
        }
    }
    View Code

    G.It is all about wisdom(最短路+二分)

    题意:

      给出一个图,图中的每条边有使用的最低限制值和花费。问从1走到n在总花费小于k的前提下的最小限制值是多少。

    题解:

      标准的二分套最短路的题型。二分最小的限制值即可。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5+10;
    const int inf = 0x3f3f3f3f;
    int t;
    int n, m, k;
    int u, v, c, l, r;
    int vis[N], dis[N];
    struct node {
        int to, v, lim;
        node(int a, int b, int c) {
            to = a; v = b; lim = c;
        }
    };
    vector<node> g[N];
    bool check(int x) {
        queue<int> q;
        for(int i = 1; i <= n; i++) vis[i] = 0, dis[i] = inf;
        q.push(1);
        vis[1] = 1;
        dis[1] = 0;
        while(!q.empty()) {
            int v = q.front();
            q.pop();
            vis[v] = 0;
            int len = g[v].size();
            for(int i = 0; i < len; i++) {
                if(g[v][i].lim > x) continue;
                if(g[v][i].v+dis[v] < dis[g[v][i].to]) {
                    dis[g[v][i].to] = g[v][i].v+dis[v];
                    if(!vis[g[v][i].to]) {
                        q.push(g[v][i].to);
                        vis[g[v][i].to] = 1;
                    }
                }
            }
        }
        if(dis[n] < k) return 1;
        return 0;
    }
    int main() {
        scanf("%d", &t);
        while(t--) {
            scanf("%d%d%d", &n, &m, &k);
            r = 0;
            for(int i = 1; i <= n; i++) g[i].clear();
            while(m--) {
                scanf("%d%d%d%d", &u, &v, &c, &l);
                g[u].push_back(node(v, c, l));
                g[v].push_back(node(u, c, l));
                r = max(r, l);
            }
            l = 1;
            while(l<=r) {
                int mid = l+r>>1;
                if(check(mid)) r = mid-1;
                else l = mid+1;
            }
            if(check(r+1)) printf("%d
    ", r+1);
            else puts("-1");
            
        }
    }
    View Code

    I.Salem

    题意:

      给出n个数,求数对中最大的hamming距离。

    题解:

      每两个数求一下异或之后二进制下1个数量即可,输出最大值。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int t, n;
    int a[105];
    int main() {
        scanf("%d", &t);
        while(t--) {
            int ans = 0;
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) {
                scanf("%d", &a[i]);
                for(int j = 1; j < i; j++) {
                    int p = a[i]^a[j], cnt = 0;
                    for(int k = 20; k >= 0; k--) {
                        if(p&(1<<k)) cnt++;
                    }
                    ans = max(ans, cnt);
                }
            }
            printf("%d
    ", ans);
        }
    }
    View Code

    J.Game

    题意:

      给出合并规则表。两个人轮流进行操作,每次选择从最左面或者最右面开始每两个合并成一个。如果最后剩的是元音字符,就是Salah获胜。否则Marzo获胜。

    题解:

      暴力维护每一种情况。用1表示S获胜,0表示M获胜。

      当S操作时,若两种情况存在1,则当前为1。

      当M操作时,若两种情况存在0,则当前为0。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e4+10;
    int t;
    int tot;
    int len[N];
    char s[N][N];
    char g[30][30];
    char cmp[5] = {'a', 'e', 'i', 'o', 'u'};
    bool dfs(int num, int k) {
        if(len[num] < 3) {
            char c;
            if(len[num]==1) c = s[num][0];
            else c = g[s[num][0]-'a'][s[num][1]-'a'];
            for(int i = 0; i < 5; i++) if(c==cmp[i]) return true;
            return false;
        }
        ++tot;
        for(int i = 0; i < len[num]; i+=2) {
            if(i==len[num]-1) s[tot][i/2] = s[num][i];
            else s[tot][i/2] =  g[s[num][i]-'a'][s[num][i+1]-'a'];
        }
        len[tot] = (len[num]+1)/2;
        bool res = dfs(tot, k^1);
        if(len[num]&1) {
            ++tot;
            s[tot][0] = s[num][0];
            for(int i = 1; i < len[num]; i+=2) {
                s[tot][i/2+1] =  g[s[num][i]-'a'][s[num][i+1]-'a'];
            }
            len[tot] = (len[num]+1)/2;
            if(k) res &= dfs(tot, k^1);
            else res |= dfs(tot, k^1);
        }
        return res;
    }
    int main() {
        scanf("%d", &t);
        while(t--) {
            tot = 0;
            for(int i = 0; i < 26; i++) scanf("%s", g[i]);
            scanf("%s", s[0]);
            len[0] = strlen(s[0]);
            if(dfs(0, 0)) puts("Salah");
            else puts("Marzo");
        }
    }
    View Code

    K.PhD math

    题意:

      给出a,b,n,p(a<b)。求a/b的前n位数中有多少字串整除p。

    题解:

      从1扫到n。维护每一位新增的余数。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e6+10;
    int t;
    ll a, b;
    int n, p;
    int bit[N];
    int v1[205], v2[205];
    ll ans;
    int main() {
        scanf("%d", &t);
        while(t--) {
            ans = 0;
            memset(v1, 0, sizeof(v1));
            memset(v2, 0, sizeof(v2));
            scanf("%lld%lld%d%d", &a, &b, &n, &p);
            for(int i = 1; i <= n; i++) {
                a *= 10;
                bit[i] = a/b;
                a = a%b;
            }
            for(int i = 1; i <= n; i++) {
                for(int j = 0; j < p; j++) {
                    if(i&1) v1[j] = 0;
                    else v2[j] = 0;
                }
                for(int j = 0; j < p; j++) {
                    if(i&1) v1[(j*10+bit[i])%p] += v2[j];
                    else v2[(j*10+bit[i])%p] += v1[j];
                }
                if(i&1) v1[bit[i]%p]++, ans += v1[0];
                else v2[bit[i]%p]++, ans += v2[0];
            }
            printf("%lld
    ", ans);
        }
    }
    View Code

    L.Candy Jars(博弈)

    题意:

      N个罐子,每个罐子有一定数量的糖。两个人轮流操作,每次选定一罐,把其他罐中的糖都扔掉。然后把选定罐中的糖任意分配给每个罐,但要保证每个罐中都有糖。不能操作者判输。

    题解:

      只要有一个罐子糖数必胜则操作者必胜。

      当所有罐子糖数小于N时无法给所有罐子分配糖,必输。

      当存在罐子糖数在[N,N(N-1)]时,可以把糖分成必输态,即分成所有罐子糖数小于N的状态,这时必胜。

      然后举例发现N(N-1)是一个循环节,取模就可以了。

    #include <bits/stdc++.h>
    using namespace std;
    int t, n;
    int k;
    int main() {
        scanf("%d", &t);
        while(t--) {
            scanf("%d", &n);
            int ans = 0;
            for(int i = 1; i <= n; i++) {
                scanf("%d", &k);
                k %= n*(n-1);
                if(k==0 || k > n-1) ans = 1;
            }
            if(ans) puts("Alice");
            else puts("Bob");
        }
    }
    View Code

    M.Building Force Fields(dp)

    题意:

      按x升序给出n个点的二维坐标,并保证没有两个点x坐标相同。可以在任意两个点之间连边,最后要保证每个点都在连边之下(或在连边上)。问最小的连边总长。

    题解:

      dp[i]表示第i个点结尾的最小总连边长。

      转移是枚举i向第j(1<=j<i)个点连边,要保证连边上方无点。即第i和第j个点的斜率比第i个点和(j,i)范围内的点的斜率都小。最后取最小值。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int t, n;
    double dp[1005];
    struct node {
        ll x, y;
    }a[1005];
    double dis(int n1, int n2) {
        return sqrt((a[n1].x-a[n2].x)*(a[n1].x-a[n2].x)+(a[n1].y-a[n2].y)*(a[n1].y-a[n2].y));
    }
    int main() {
        scanf("%d", &t);
        while(t--) {
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) scanf("%lld%lld", &a[i].x, &a[i].y);
            dp[1] = dis(1, 2);
            for(int i = 2; i <= n; i++) {
                int pos = i-1;
                dp[i] = min(dp[i-2], dp[i-1])+dis(i, i-1);
                for(int j = i-2; j >= 1; j--) {
                    if((a[i].y-a[pos].y)*(a[i].x-a[j].x) >= (a[i].y-a[j].y)*(a[i].x-a[pos].x)) {
                        dp[i] = min(dp[i], min(dp[j-1], dp[j])+dis(i, j));
                        pos = j;
                    }
                }
            }
            printf("%.6lf
    ", dp[n]);
        }
    }
    View Code
  • 相关阅读:
    前台的js对象数组传到后台处理。在前台把js对象数组转化为json字符串,在后台把json字符串解析为List<>
    ef中用lambda expressions时要注意(m=>m.id ==b ) 此时的b只能是基本的数据类型 。连属性都不能用
    你是否有遇到过某个实体类字段(属性)过多的情况,不想每次点的话戳进来(C# 反射)
    razor使用注意点........
    让简历在15秒内吸引招聘者《我的前程我做主》六
    JavaScript学习总结(十六)——Javascript闭包(Closure)
    C#操作XML的完整例子——XmlDocument篇(转载,仅做学习之用)
    C#操作XML方法集合
    图片超链接作为下载来处理
    架构师手记
  • 原文地址:https://www.cnblogs.com/Pneuis/p/9130470.html
Copyright © 2011-2022 走看看