2018 Multi-University Training Contest 4

Problem B. Harvest of Apples

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

const int maxn = 1e5 + 50;
typedef long long ll;
const ll mod = 1e9 + 7;
ll fac[maxn], sing[maxn], inv[maxn];
void init(int n)
{
    fac[0] = sing[0] = inv[0] = fac[1] = sing[1] = inv[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        fac[i] = fac[i - 1] * i % mod;
        sing[i] = (mod - mod / i) * sing[mod % i] % mod;
        inv[i] = inv[i - 1] * sing[i] % mod;
    }
}
ll C(int n, int m)
{
    ll res =  fac[n]* inv[m] % mod * inv[n - m] % mod;
   // printf("%d %d %lld
",n, m, res);
    return res;
}
struct Seg
{
    int l, r, belong, id;
}seg[maxn];
ll ans[maxn];
bool cmp(Seg A, Seg B)
{
    if(A.belong == B.belong) return A.r < B.r;
    return A.l < B.l;
}
int main()
{
    init(1e5 + 5);
    int block = sqrt(1e5);
    int T; scanf("%d", &T);
    for(int p = 1; p <= T; p++)
    {
        scanf("%d %d", &seg[p].l, &seg[p].r);
        seg[p].belong = seg[p].l / block;
        seg[p].id = p;
    }
    sort(seg + 1, seg + T + 1, cmp);
    int l = 0, r = 0;
    ll res = 1;
    for(int i = 1; i <= T; i++)
    {
        while(l < seg[i].l)
        {
            res = (res * 2LL % mod + mod - C(l, r)) % mod;
            l++;
        }
        while(l > seg[i].l)
        {
            l--;
            res = (res + C(l, r)) * sing[2] % mod;
        }
        while(r < seg[i].r)
        {
            r++;
            res = (res + C(l, r)) % mod;
        }
        while(r > seg[i].r)
        {
            res = (res + mod - C(l, r)) % mod;
            r--;
        }
        ans[seg[i].id] = res;
       // printf("%lld
", ans[seg[i].id]);
    }
    for(int i = 1; i <= T; i++)
    {
        printf("%lld
", ans[i]);
    }
    return 0;
}
Code

Problem E. Matrix from Arrays

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e3 + 50;
int a[maxn];
int sum = 0;
int m[50][50];
int L;
ll solve(ll x, ll y)
{
    x++, y++;
    ll res = 0;
    int cntx = x / (2 * L);
    int cnty = y / (2 * L);
    res += (ll)cntx * cnty * sum; ///加上整块的
    int tempx = x - cntx * 2 * L;
    int tempy = y - cnty * 2 * L;
    ll sum1 = 0 ,sum2 = 0;
    for(int i = 0; i < tempx; i++) ///加上半块半块的
    {
        for(int j = 0; j < 2 * L; j++)
        {
            sum1 += m[i][j];
        }
    }
    for(int i = 0; i < 2 * L; i++)
    {
        for(int j = 0; j < tempy; j++)
        {
            sum2 += m[i][j];
        }
    }
    res += sum1 * cnty;
    res += sum2 * cntx;
    ///加上残块的
    for(int i = 0; i < tempx; i++)
    {
        for(int j = 0; j < tempy; j++)
        {
            res += m[i][j];
        }
    }
    return res;
}

int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &L);
        sum = 0;
        for(int i = 0; i < L; i++) scanf("%d", &a[i]), sum += 4 * L * a[i];
        int cur = 0;
        for(int i = 0; i < 45; i++)
        {
            for(int j = 0; j <= i; j++)
            {
                m[j][i - j] = a[cur];
                cur = (cur + 1) % L;
            }
        }
       /* for(int i = 0; i < 10; i++)
        {
            for(int j = 0; j < 10; j++)
            {
                printf("%3d ", m[i][j]);
            }
            printf("
");
        }*/
       // printf("%lld
",solve(1, 2));
        int q; scanf("%d", &q);
        while(q--)
        {
            int x1, y1, x2, y2;
            scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
            ll ans = solve(x2, y2) - solve(x2, y1 - 1) - solve(x1 - 1, y2) + solve(x1 - 1, y1 - 1);
           // printf("%lld %lld %lld %lld
",solve(x2, y2), solve(x2, y1 - 1), solve(x1 - 1, y2), solve(x1 - 1, y1 - 1));
            printf("%lld
", ans);
        }
    }
    return 0;
}
Code

Problem J. Let Sudoku Rotate

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

char s[20][20], w[5][5];
int vis[50];
int ans = 100;
int tmp[5][5];
void Rota(int a, int b) ///顺时针旋转90度
{
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            tmp[j][3 - i] = s[a + i][b + j];
        }
    }
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            s[a + i][b + j] = tmp[i][j];
        }
    }
}
int cnt = 0;
int check(int a, int b)
{
    ///memset(vis, 0, sizeof(vis)); 从dls那里学了个姿势,不用每次memset了
    for(int i = a; i < a + 4; i++)  ///判断我这个小块的前面有没有重复的
    {
        cnt++;
        for(int j = 0; j < b + 4; j++)
        {
           // printf("%d
", s[i][j]);
            if(vis[s[i][j]] == cnt)
            {
                //printf("%d %d %d
", i, j, cnt);
                return 0;
            }
            vis[s[i][j]] = cnt;
        }
    }
    for(int i = b; i < b + 4; i++)
    {
        cnt++;
        for(int j = 0; j < a + 4; j++)
        {
            if(vis[s[j][i]] == cnt)
                return 0;
            vis[s[j][i]] = cnt;
        }
    }
    return 1;
}
void dfs(int x, int y, int sum)
{
    if(x == 4)
    {
        ans = min(ans, sum);
        return;
    }
    if(sum >= ans) return;
    if(y == 4) return dfs(x + 1, 0, sum);
    for(int i = 0; i < 4; i++)
    {
        if(check(x * 4, y * 4))
        {
            dfs(x, y + 1, sum + i);
        }
        Rota(x * 4, y * 4);
    }
}
int main()
{
    int T; scanf("%d", &T);
    while(T--)
    {
        for(int i = 0; i < 16; i++) scanf("%s", s[i]);
        for(int i = 0; i < 16; i++)
        {
            for(int j = 0; j < 16; j++)
            {
                s[i][j] = s[i][j] - '0';
            }
        }
        memset(vis, 0, sizeof(vis));
        ans = 100;
        cnt = 0;
        dfs(0, 0, 0);
        printf("%d
", ans);
    }
    return 0;
}
Code

Problem G. Depth-First Search

      终于把思路理清楚了。

      整体思想是逐位的思想。

      首先考虑$b[1]$,我们发现如果$root<b[1]$,那后面怎么排列都满足条件。那我们需要统计这些情况,我们发现每一个点的孩子节点是$deg[i]-1$,只有根节点的孩子节点是$deg[i]$,那我们可以维护一个$res$,令$res=prod_{i=1}^n (deg[i]-1)!$。再计算以$root$为根的排列情况,就$ans += res * deg[root]$就可以了。

      考虑完$root<b[1]$的情况,进一步考虑$root=b[1]$的情况。此时先将$res$更新为$res=res*deg[b[1]]$,代表此时以$b[1]$为根出发。和前一种情况类似,走的下一个节点$<b[2]$,那后面怎么排列都满足条件。查询$root$子树中节点$<b[2]$的个数$t$$($可以用$n$颗树状数组解决$)$,那$ans = ans + frac{res*t}{deg[b[1]]}$,就是我从$t$中任选一个点走下一步,$b[1]$少了能任意选择的情况,此时$res$就要修改为$res=frac{res}{deg[b[1]]}$,$deg[b[1]]--$。然后再去考虑$second($第二个遍历点$)=b[2]$的情况。

      后面的点依次像上面一样遍历。

      慎用$memset!!!$

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 50;
int b[maxn];
int fac[maxn], sing[maxn], inv[maxn];
int deg[maxn];
vector<int> g[maxn];
const ll mod = 1e9 + 7;
void init(int n)
{
    fac[0] = fac[1] = sing[0] = sing[1] = inv[0] = inv[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        fac[i] = (ll)fac[i - 1] * i % mod;
        sing[i] = (ll)(mod - mod / i) * sing[mod % i] % mod;
        inv[i] = (ll)inv[i - 1] * sing[i] % mod;
    }
}
struct Tree
{
    vector<int> T;
    int n;
    void init(int _n)
    {
        n = _n;
        T.resize(n + 1);
        for(int i = 0; i <= n; i++) T[i] = 0;
    }
    void add(int x, int v)
    {
        x++;
       // printf("%d %d
", x, v);
        for(int i = x; i <= n; i += (i & -i)) T[i] += v;
    }
    int query(int x)
    {
        x++;
        //printf("%d ", x);
        if(x > n) x = n; ///所有的节点都比我小
        //printf("%d
", x);
        int res = 0;
        for(int i = x; i > 0; i -= (i & -i)) res += T[i];
        return res;
    }
}tr[maxn];
int pre[maxn];
void dfs1(int u, int fa)
{
    sort(g[u].begin(), g[u].end()); ///对子节点排序,方便在子节点中离散化存储
    pre[u] = fa;
    tr[u].init(g[u].size());
    for(int i = 0; i < g[u].size(); i++)
    {
        int v = g[u][i];
        if(v == fa) continue;
        int tmp = lower_bound(g[u].begin(), g[u].end(), v) - g[u].begin();
        //printf("%d ", v);
        tr[u].add(tmp, 1);
        deg[v]--;
        dfs1(v, u);
    }
}
ll ans = 0, res = 0;
int n, cur = 1, flag = 0;
void dfs2(int u)
{
    if(cur >= n || flag || (!u)) return;  /// !u 退回到根节点
    if(deg[u]) ///全部子节点已经被排列
    {
        int tmp = lower_bound(g[u].begin(), g[u].end(), b[cur + 1]) - g[u].begin();
        //printf("%d ", b[cur + 1]);
        int cnt = tr[u].query(tmp - 1);
        ans = (ans + res * cnt % mod * sing[deg[u]] % mod) % mod;
        if(pre[b[cur + 1]] != u) ///不用往下继续了,因为给的b序列就不是一个dfs序列
        {
            flag = 1;
            return;
        }
        cur++;
        tmp = lower_bound(g[u].begin(), g[u].end(), b[cur]) - g[u].begin();
        //printf("%d ", b[cur]);
        tr[u].add(tmp, -1);
        res = res * sing[deg[u]] % mod;
        deg[u]--;
        dfs2(b[cur]);
    }
    else dfs2(pre[u]);
}
int main()
{
    init(1e6);
    int T; scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) scanf("%d", &b[i]), g[i].clear() ,deg[i] = 0;
        for(int i = 1; i < n; i++)
        {
            int u, v; scanf("%d %d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);
            deg[u]++, deg[v]++;
        }
        ans = 0, res = 1;
        for(int i = 1; i <= n; i++)
        {
            res = res * fac[deg[i] - 1] % mod;
        }
        for(int i = 1; i < b[1]; i++)
        {
            ans = (ans + res * deg[i]) % mod;
        }
        cur = 1, flag = 0;
        res = res * deg[b[1]] % mod;
        dfs1(b[1], 0);
        dfs2(b[1]);
        printf("%lld
", ans);
    }
    return 0;
}
Code
原文地址:https://www.cnblogs.com/littlepear/p/9417334.html