南京网络赛

A题  An Olympian Math Problem:

求S(n) = 1*1! + 2*2! + 3*3! + 4*4! + ... + (n-1)*(n-1)!

链接: https://nanti.jisuanke.com/t/30990

所以直接输出n-1完事

#include <bits/stdc++.h>

using namespace std;

long long n;

int main()
{
    int t;
    scanf("%d", &t);
    while (t--) {
        scanf("%lld", &n);
        printf("%lld\n", n-1);
    }
    return 0;
}
View Code

 

C. GDY 

链接: https://nanti.jisuanke.com/t/30992

模拟题: 

题意就是  n个人打牌, 然后有m张牌的栈,每个人最开始依次从栈取5张牌, 栈保证初始时,每个人至少有一张牌.

                规则1 : 牌除了一种例外外, 必须安装 3 --> 4 --> 5 --> 6 --> 7 --> 8 --> 9 --> 10 --> 11 --> 12 --> 13 --> 1 --> 2 的顺序打出

                规则3 : 例外就是, 如果不能按照顺序,但是前面打出的牌小于2,同时你有2,你可以打出2.

                规则2 : 你如果同时有2和下一张牌, 你会优先打出下一张牌.

                规则4 : 如果可以打出牌,那么一定会出牌.

                规则5 : 如果没有人能出牌,那么从最后一个出牌的人开始,每个人都抽一张牌.然后从最后一个出牌的人继续出牌.  

                规则6 : 第一个出牌的人,出的是他牌面里最小的牌.

                规则7 : 如果栈没有牌了,而且有人不能出牌了,则忽略这个人.

                规则8 : 如果有人牌打完了,那么这人就是赢家,其他人的得分就是他们手上剩下的牌的总和.

好的 按时规则模拟.

因为有次序,同时我们可以处理一下,把1变成14 2变成15,然后用一个multiset来存会方便很多.

然后我们注意到,对于当前出牌人来说,如果他出的牌有n-1个人不能出牌,那么就从他开始抽牌.

所以我们可以定义一个cnt计数器,表示多少个人不能出牌.  

#include <set>
#include <cstdio>

using namespace std;

multiset<int> se[256];
int st[25600];
int top;

int main()
{
    int t, n, m, i, j, pos, now, old, cnt;
    multiset<int>::iterator it1, it2;
    scanf("%d", &t);
    for (int cas=1; cas<=t; cas++) {
        scanf("%d%d", &n, &m);
        for (i=1; i<=n; ++i) se[i].clear();
        for (i=m; i; --i) {
            scanf("%d", st+i);
            if (st[i] <= 2) st[i] += 13;
        }
                        
        top = m;
        for (i=1; i<=n; ++i) 
            for (j=1; j<=5 && top; ++j) 
                se[i].insert(st[top--]);
        old = *se[1].begin() - 1;
        now = 1;
        bool isgameover = false;
        while (!isgameover) {
            cnt = 0;
            while (1) {    
                if (now > n) now = 1;
                if (cnt == n-1) break; // 因为经过n-1次 now也回到了出牌人,所以直接break 
                it1 = se[now].end(); it1--;
                it2 = se[now].find(old+1);
                if (old==15) {
                    now--;
                    break;
                }
                if (it2 != se[now].end()) {
                    old = *it2;
                    se[now].erase(it2);
                    if (se[now].empty()) {
                        isgameover = true;
                        break;
                    }
                    now++;
                    cnt = 0;
                } else if (*it1 == 15) {
                    old = 15;
                    se[now].erase(it1);
                    if (se[now].empty()) {
                        isgameover = true;
                        break;
                    }
                    break;  // 以后后面可能没人可以再出牌了 所以直接break. 当然 把 break 改写成 now++; cnt=0; 也是等价的. 
                } else cnt++, now++;
            }
            if (isgameover) break;
            if (now < 1) now = n;
            for (pos=now, i=1; i<=n && top; ++i, ++pos) {
                if (pos > n) pos = 1;
                se[pos].insert(st[top--]);
            }
            old = *se[now].begin();
            se[now].erase(se[now].begin());
            if (se[now].empty()) {
                isgameover = true;
                break;
            }
            now++;
        }
        printf("Case #%d:\n", cas);
        for (i=1; i<=n; ++i) {
            if (se[i].empty()) printf("Winner\n");
            else {
                int res = 0;
                for (int it : se[i]) {
                    res += it<=13 ? it : it-13;
                }
                printf("%d\n", res);
            }
        }
    }
    
    return 0;
}
View Code

 

 

L. Magical Girl Haze: 

链接: https://nanti.jisuanke.com/t/31001

给你一副有向图,从1出发,可以最多可以让k条路径为0,求到n的最短路径 (K<=10) 

我们发现K特别小.

所以考虑一下Dij, 然后我们把路变为0和不修改路都添加进去, 直接跑就OK了

#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <iostream>

using namespace std;

typedef long long ll;

const int maxn = 100500;

struct Edge {
    int lst;
    int to;
    ll val;
}edge[maxn*2];
int head[maxn];
int qsz;

int qn, qk;

inline void add(int u, int v, ll val) {
    edge[qsz].lst = head[u];
    edge[qsz].to  = v;
    edge[qsz].val = val;
    head[u] = qsz++;
}


struct nobe {
    int to;
    int k;
    ll  w;
    nobe () { }
    nobe (int tt, int kk, ll ww) : to(tt), k(kk), w(ww) { }
    bool operator < (const nobe &a) const {
        return w > a.w;
    }
};

bool vis[11][maxn];
ll  dist[11][maxn];

ll Dij(int ed) {
    //cout << ed << endl;
    priority_queue<nobe> pq;
    nobe now;
    int i, u, k, v, j;
    ll w;
    
    for (i=1; i<=qn; ++i) {
        for (j=0; j<=qk; ++j) {
            dist[j][i] = 862621363;
             vis[j][i] = false;
        }
    }
    
    dist[0][1] = 0;
    pq.push(nobe(1, 0, 0));
    while (!pq.empty()) {
        now = pq.top(); pq.pop();
        u = now.to; k = now.k; w = now.w;
        if (vis[k][u]) continue;
        vis[k][u] = true;
        for (i=head[u]; i; i=edge[i].lst) {
            v = edge[i].to;
            if (k<qk && dist[k+1][v] > w) {
                dist[k+1][v] = w;
                pq.push(nobe(v, k+1, w));
            }
            if (dist[k][v] > w + edge[i].val) {
                dist[k][v] = w + edge[i].val;
                pq.push(nobe(v, k, dist[k][v]));
            }
        }
    }
    
    ll res = 0x3fffffffffffffff;
    for (i=0; i<=qk; ++i) 
        res = min(res, dist[i][ed]);
    return res;
}

int main()
{
//    freopen("E:\\input.txt", "r", stdin);
    int t, n, m, k, u, v, c, i;
    scanf("%d", &t);
    while (t--) {
        memset(head, 0, sizeof(head)); qsz = 1;
        scanf("%d%d%d", &n, &m, &k);
        qk = k; qn = n;
        for (i=1; i<=m; ++i) {
            scanf("%d%d%d", &u, &v, &c);
            add(u, v, (ll)c);
        }
        printf("%lld\n", Dij(n));
    }
    
    return 0;
}
View Code

 

posted @ 2018-09-01 21:06  过路人1998  阅读(156)  评论(0编辑  收藏  举报