模拟赛小结:2018-2019 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2018)

比赛链接:传送门

两个半小时的时候横扫了铜、银区的所有题,签到成功混进金区。奈何后面没能开出新的题。

最后一个小时的时候xk灵机一动想出了D题的做法,讨论了一波感觉可行,赶紧去敲。结束前2分钟终于过了样例结果WA3。

赛后10分钟,xk改了两个bug就过了D。。。。离金最近的一场(又来?)。


Problem B. Baby Bites 00:11 (-1) Solved by Dancepted

很明显的签到题,题面短又水。(那你还WA了一发?555我错了,我把循环里的j手滑写成了i)

代码:

#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 100005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '
'
#define lowbit(x) (x&-x)
 
using namespace std;
typedef long long ll;
typedef double db;
 
/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
    int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
    do{++len; c[len] = x%10 + '0';} while (x /= 10);
    for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }
 
int main() {
    int n;
    cin >> n;
    bool ans = true;
    for (int i = 1; i <= n; i++) {
        string s;
        cin >> s;
        if (s[0] == 'm') {
            continue;
        }
        int a = 0;
        for (int j = 0; j < sz(s); j++)
            a = a * 10 + s[j] - '0';
        if (a != i) {
            ans = false;
        }
    }
    if (ans) {
        puts("makes sense");
    }
    else {
        puts("something is fishy");
    }
    return 0;
}
View Code

Problem C. Code Cleanups 00:27 (+) Solved by xk

队友签的到。

代码:

#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 2505
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '
'
#define lowbit(x) (x&-x)
 
using namespace std;
typedef long long ll;
typedef double db;
 
int a[400];
 
int main()
{
    fast;
    int n;
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        cin >> a[i];
    }
    int cnt = 0, p = 0;
    int dirty = 0;
    int ans = 0;
    for(int i = 1; i <= 365 && p < n; i++)
    {
        dirty += cnt;
        if(a[p] == i) {
            p++;
            cnt++;
        }
        if(dirty + cnt >= 20) {
            ans++;
            cnt = dirty = 0;
        }
    }
    if(cnt) ans++;
    cout << ans << endl;
}
View Code

Problem K. King's Colors 01:13 (+) Solved by Dancepted

xk乍一看是个树形dp,直接丢了给我。我也差点被xk带偏。

实际上大概是类似容斥一样的线性dp:

首先,有n个节点的树,使用了 <= i种颜色的染色方案数为 $ i * (i-1)^{n-1} $,每个节点只要和父节点不同即可,有i-1种方案,而根没有限制,有i种方案。

设$f_{i}$为恰好使用了i种颜色的染色方案数:

那么$f_{i} =  i * (i-1)^{n-1} - sum_{j=1}^{i-1} C_{i}^{j} * f_{j}$。就是 <= i种颜色的染色方案数 - $sum$(从i种颜色中选j种颜色的方案数) * j种颜色的染色方案数。

代码:$O(n^{2})$

#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 2505
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '
'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
    int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
    do{++len; c[len] = x%10 + '0';} while (x /= 10);
    for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }

#define md 1000000007
inline ll mul(ll a) {return a;}
template <typename... Args>
inline ll mul(ll a, Args ... args) {return a*mul(args...) % md;}
inline ll add(ll a) {return a;}
template <typename... Args>
inline ll add(ll a, Args ... args) {
    ll res = (a+add(args...)) % md;
    if (res < 0) res += md;
    return res;
}
inline ll fpow(ll a, ll p) {
    ll res = 1;
    for (; p; p >>= 1) {
        if (p&1) res = mul(res, a);
        a = mul(a, a);
    }
    return res;
}
inline ll getInv(ll x) { return fpow(x, md-2); }
#define MAXN 2505
ll fac[MAXN], inv[MAXN];
ll C(ll n, ll m) { if (m < 0 || m > n) return 0; return mul(fac[n], mul(inv[n-m], inv[m])); }
ll P(ll n, ll m) { return mul(fac[n], fac[n-m]); }
void init() {
    fac[0] = 1; for (int i = 1; i < MAXN; i++) fac[i] = mul(fac[i-1], i);
    inv[MAXN-1] = fpow(fac[MAXN-1], md-2); for (int i = MAXN-2; i >= 0; i--) inv[i] = mul(inv[i+1], i+1);
}


ll f[N];
int main() {
    init();
    int n; ll k; read(n, k);
    for (int i = 2; i <= n; i++) {
        int a; read(a);
    }
    for (int i = 2; i <= k; i++) {
        f[i] = mul(i, fpow(i-1, n-1));
        for (int j = 2; j <= i-1; j++) {
            ll tmp = mul(C(i, j), f[j]);
            f[i] = add(f[i], -tmp);
        }
    }
    ll ans = f[k];
    cout << ans << endl;
    return 0;
}
View Code

Problem H. House Lawn 01:39 (+) Solved by xk

在我和lh捣鼓J的时候,xk已经开出了I和H,抢键盘上机秒题。

代码:

#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define sz(x) ((int)x.size())
#define forn(i, n) for(int i = 0; i < (n); i++)
#define forab(i, a, b) for(int i = (a); i <= (b); i++)
#define mp(a,b) make_pair(a, b)
#define endl '
'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;
 
char s[105][100];
ll p[105], c[105], t[105], r[105];
 
int main()
{
    ll l, n;
    cin >> l >> n;
    forn(i, n)
    {
        scanf("
%[^,],%lld,%lld,%lld,%lld", s[i], &p[i], &c[i], &t[i], &r[i]);
    }
    ll mxp = 1e18;
    forn(i, n)
    {
        if(p[i] > mxp) continue;
        if(c[i] * t[i] * 10080 >= l * (r[i] + t[i]))
        {
            mxp = p[i];
        }
    }
    if(mxp == 1e18) {
        return puts("no such mower") * 0;
    }
    forn(i, n)
    {
        if(p[i] == mxp && (c[i] * t[i] * 10080 >= l * (r[i] + t[i])))
        {
            puts(s[i]);
        }
    }
}
View Code

Problem J. Jumbled String 01:56 (-3) Solved by lh & Dancepted

lh在01:06的时候就已经写好了代码,但是有几个特殊值没有考虑到,差点弃题。

直接计算0和1的数量n和m,得到总数量n+m,$C_{n+m}^{2}$ = a + b + c + d。如果成立就贪心地在1之间插入0,使得01的数量是正确的,那么10的数量肯定是正确的。

需要特判abcd全0或者有3个0的情况。

代码:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
long long a, b, c, d, n, m;
long long sum[100005] = {};
int main()
{
    cin >> a >> b >> c >> d;
    if (a == 0 && b == 0 && c == 0 && d == 0)
    {
        puts("1");
        return 0;
    }
    bool flag = false;
    if (a == 0 && d == 0)
        n = 1, m = 1;
    else
    {
        if (a == 0)
            n = 1;
        else
        {
            n = sqrt(a * 2);
            for (long long i = max(n - 10, 0ll); i <= n + 10; ++i)
            {
                if (i * (i - 1ll) == a * 2)
                {
                    n = i, flag = true;
                    break;
                }
            }
            if (!flag)
            {
                puts("impossible");
                return 0;
            }
        }
        if (d == 0)
            m = 1;
        else
        {
            m = sqrt(d * 2), flag = false;
            for (long long i = max(m - 10, 0ll); i <= m + 10; ++i)
            {
                if (i * (i - 1ll) == d * 2)
                {
                    m = i, flag = true;
                    break;
                }
            }
            if (!flag)
            {
                puts("impossible");
                return 0;
            }
        }
    }
    if (c == 0 && b == 0)
    {
        if (a == 0 && d)
        {
            while (m--)putchar('1');
            return 0;
        }
        else if (a && d == 0)
        {
            while (n--)putchar('0');
            return 0;
        }
    }
    long long tot = n + m;
    if (a + b + c + d != (tot - 1ll) * tot / 2)
    {
        puts("impossible");
        return 0;
    }
    for (long long i = 0; i < m; ++i)
    {
        sum[i] = b / (m - i);
        b %= (m - i), n -= sum[i];
        if (b == 0 || n == 0)
            break;
    }
    if (b)
    {
        puts("impossible");
        return 0;
    }
    for (int i = 0; i < m; ++i)
    {
        while (sum[i])putchar('0'), --sum[i];
        putchar('1');
    }
    while (n)putchar('0'), --n;
    return 0;
}
/*
1 4 2 3
*/
View Code

Problem I. Intergalactic Bidding 02:32 (+) Solved by Dancepted & xk

就是个cf div2的a、b题难度的大水题,但是要大数。

自信满满地打开eclipse发现大数不会读入,不会重载小于号排序。。。

只能老老实实切回vscode,掏出尘封多年的c++大数板子,一字一句地抄上去(模拟现场赛)。

代码:O(n*logn*logs)

#include <iostream>
#include <istream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 1005
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '
'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
    int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
    do{++len; c[len] = x%10 + '0';} while (x /= 10);
    for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }

struct bigInt{
    int len, d[N];
    void clean() {
        while (len > 1 && !d[len-1]) len--;
    }
    bigInt() {memset(d, 0, sizeof d); len = 1;}
    bigInt(int num) {*this = num;}
    bigInt operator = (int num) {
        char s[20];
        sprintf(s, "%d", num);
        *this = s;
        return * this;
    }
    bigInt operator = (const char* num) {
        memset(d, 0, sizeof d);
        len = strlen(num);
        for (int i = 0; i < len; i++)
            d[i] = num[len-1-i] - '0';
        clean();
        return *this;
    }
    bool operator < (const bigInt& b) const {
        if (len != b.len) return len < b.len;
        for (int i = len-1; i >= 0; i--)
            if (d[i] != b.d[i])
                return d[i] < b.d[i];
        return false;
    }
    bool operator == (const bigInt& b) const { return !(b < *this) && !(*this < b); }
    bigInt operator + (const bigInt& b) const {
        bigInt c = *this;
        c.len = max(len, b.len) + 1;
        for (int i = 0; i < c.len; i++) {
            c.d[i] += b.d[i];
            c.d[i+1] += c.d[i] / 10;
            c.d[i] %= 10;
        }
        c.clean();
        return c;
    }
    bigInt operator - (const bigInt& b) {
        bigInt c = *this;
        int i;
        for (i = 0; i < b.len; i++) {
            c.d[i] -= b.d[i];
            if (c.d[i] < 0) c.d[i] += 10, c.d[i+1]--;
        }
        while (c.d[i] < 0) c.d[i++] += 10, c.d[i]--;
        c.clean();
        return c;
    }
};

istream& operator >> (istream& in, bigInt& x) {
    string s; in >> s;
    x = s.c_str();
    return in;
}

struct Node{
    string name;
    bigInt val;
    bool operator < (const Node& x) const {
        return val < x.val;
    }
}nodes[N];

vector <string> ans;
int main() {
    ios::sync_with_stdio(), cin.tie(0), cout.tie(0);
    int n; bigInt sum;
    cin >> n >> sum;
    for (int i = 1; i <= n; i++) {
        cin >> nodes[i].name >> nodes[i].val;
    }
    sort(nodes+1, nodes+1+n);
    for (int i = n; i >= 1; i--) {
        if (nodes[i].val < sum || nodes[i].val == sum) {
            sum = sum - nodes[i].val;
            ans.push_back(nodes[i].name);
        }
    }
    if (sum.len == 1 && sum.d[0] == 0) {
        cout << ans.size() << endl;
        for (string& s: ans) {
            cout << s << endl;
        }
    }
    else {
        cout << 0 << endl;
    }
    return 0;
}
View Code

补题:

Problem E. Explosion Exploit(最短路 + 二分答案 + dp)

先跑n次Dijkstra得到两两之间的距离$dis_{i,j}$。

然后二分答案+dp确认。

$dp_{i}$表示在答案为mid时,第i个订单允许的最晚出发时间。

枚举骑手在送第i单时,连续送到第j个订单结束,才回披萨店取餐,则对于所有的k(i <= k <= j),满足下面条件的最大值,是$dp_{i}$的一个可能的值:

$dp_{i} + dis_{1, u_{i}} + sum_{l=i+1}^{k}dis{u_{l}, u_{l-1}} + dis_{1, u_{k}} <= dp_{k+1}$。

最后的$dp_{i}$就是对所有的可能值取max。

如果存在$dp_{i} < t_{i}$,则说明不存在方案使得第i个单子在答案为mid时能被准时送到,则不可行。否则可行。

代码:$O(n^{2}logn)$

#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define sz(x) ((int)x.size())
#define forn(i, n) for(int i = 0; i < (n); i++)
#define forab(i, a, b) for(int i = (a); i <= (b); i++)
#define mp(a,b) make_pair(a, b)
#define endl '
'
#define lowbit(x) (x&-x)
using namespace std;
typedef long long ll;
typedef double db;

const int maxn = 1005;
struct edge
{
    int to;
    ll len;
};

struct node
{
    int id;
    ll dis;
    bool operator < (const node &a) const {
        return dis > a.dis;
    }
};

ll dis[maxn][maxn];
vector<edge> g[maxn];

void dij(int x)
{
    priority_queue<node> q;
    memset(dis[x], 0x3f, sizeof(dis[x]));
    dis[x][x] = 0;
    q.push(node{x, 0});
    while(!q.empty())
    {
        node t = q.top(); q.pop();
        int u = t.id;
        if(t.dis > dis[x][u]) continue;
        forn(i, sz(g[u]))
        {
            edge &e = g[u][i];
            if(dis[x][e.to] > dis[x][u] + e.len)
            {
                dis[x][e.to] = dis[x][u] + e.len;
                q.push(node{e.to, dis[x][e.to]});
            }
        }
    }
}

int n, m, k;
ll s[maxn], u[maxn], t[maxn];
ll dp[maxn];

bool check(ll x)
{
    // cout << x << endl;
    dp[k + 1] = 1e16;
    for(int i = k; i > 0; i--)
    {
        ll sumdis = dis[1][u[i]];
        ll temp = s[i] + x - sumdis;
        dp[i] = min(s[i] + x - sumdis, dp[i + 1] - 2 * dis[1][u[i]]);
        for(int j = i + 1; j <= k; j++)
        {
            sumdis += dis[u[j]][u[j - 1]];
            temp = min(temp, s[j] + x - sumdis);
            ll tt = min(temp, dp[j + 1] - dis[1][u[j]] - sumdis);
            if(tt >= t[j])
                dp[i] = max(dp[i], tt);
        }
        if (dp[i] < t[i]) return false;
        // cout << dp[i] << ' ';
    }
    // cout << endl;
    return dp[1] >= 0;
}

int main()
{
    fast;
    cin >> n >> m;
    forn(i, m)
    {
        int u, v; ll l;
        cin >> u >> v >> l;
        g[u].push_back(edge{v,l});
        g[v].push_back(edge{u,l});
    }
    forab(i, 1, n)
        dij(i);
    cin >> k;
    forab(i, 1, k)
    {
        cin >> s[i] >> u[i] >> t[i];
    }
    ll l = -1, r = 1e16;
    while (r - l > 1)
    {
        ll mid = (l + r) / 2;
        if(check(mid))
            r = mid;
        else
            l= mid;
    }
    cout << r << endl;
    return 0;
}
View Code

Problem D. Delivery Delays(状压dp)

直接状压的话空间是$7^{10} ≈ 2e9$,考虑对1-6数值的数量状压。

这样可以用dp来计算空间复杂度,5个人分到6个数值250左右个方案。两边有10个人,平方一下大概是5e4个。

实现的话用dfs比较方便,用map记忆化一下就好(vscode不知为啥不能用unordered_map)。

参考博客:传送门

代码:

#include <iostream>
#include <map>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#include <type_traits>
#include <vector>
#include <string>
#include <queue>
#include <stack>
#include <iomanip>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 5
#define M 100005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '
'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }
template <typename T>
inline void write(T x) {
    int len = 0; char c[21]; if (x < 0) putchar('-'), x = -x;
    do{++len; c[len] = x%10 + '0';} while (x /= 10);
    for (int i = len; i >= 1; i--) putchar(c[i]);
}
template <typename T, typename... Args>
inline void write(T x, Args ... args) { write(x), write(args...); }

int a[2][7];
ll haxi() {
    ll res = 0;
    for (int i = 0; i < 2; i++) {
        for (int j = 1; j <= 6; j++) {
            res = res * 10 + a[i][j];
        }
    }
    return res;
}

map<ll, db> MP;
// unordered_map<ll, db> MP; 
db dfs(ll sta, int resd) {
    if (MP.count(sta)) return MP[sta];
    if (sta < 1000000)
        return MP[sta] = 1;
    if (resd == 0)
        return MP[sta] = 0;

    int sum = 0;
    for (int i = 0; i < 2; i++) {
        for (int j = 1; j <= 6; j++) {
            sum += a[i][j];
        }
    }

    db res = 0;
    for (int i = 0; i < 2; i++) {
        for (int j = 1; j <= 6; j++) {
            if (!a[i][j])
                continue;
            a[i][j]--, a[i][j-1]++;
            db tmp = dfs(haxi(), resd-1);
            a[i][j]++, a[i][j-1]--;
            res += (db)a[i][j] / sum * tmp;
        }
    }
    return MP[sta] = res;
}

int main() {
    int n, m, d; read(n, m, d);
    for (int i = 1; i <= n; i++) {
        int x; read(x);
        a[1][x]++;
    }
    for (int i = 1; i <= m; i++) {
        int x; read(x);
        a[0][x]++;
    }
    db ans = dfs(haxi(), d);
    printf("%.8lf
", ans);
    return 0;
}
View Code

总结:

切完银牌题之后有点飘没有静下心思想E的做法,优化状态的数量是想到了的,但是没有底气继续写。

xk写D的时候我觉得xk的debug手法太糙了,忍不住抢了键盘qwq,而xk赛后10分钟改了两个bug就过了D,这里我应该也要背个锅吧,痛失金牌。

lh今天好像掉线了?

原文地址:https://www.cnblogs.com/Lubixiaosi-Zhaocao/p/11821218.html