【11.1校内测试】【快速幂DP】【带权并查集】【模拟】

Solution

$jzy$大佬用了给的原根的信息,加上矩阵快速幂150行QAQ

然而$yuli$大佬的做法不仅好懂,代码只有50行!

快速幂的思想,把m看成要组成的区间总长度,每次将两段组合得到新的长度。

定义$g[i]$表示当前x为$i$时的方案数,用来最后计算期望,在快速幂中相当于ans,定义$f[i]$代表a,是初始要用来组合的长度为1的方案,再用一个辅助数组转移即可。

Code

#include<bits/stdc++.h>
#define MOD 1000000007
#define LL long long
using namespace std;

LL mpow(LL a, LL b) {
    LL ans = 1;
    for(; b; b >>= 1, a = a * a % MOD)
        if(b & 1)    ans = ans * a % MOD;
    return ans;
}

int n, m, mod, a;
LL f[1005], fz[1005], g[1005];
int main() {
    freopen("rand.in", "r", stdin);
    freopen("rand.out", "w", stdout);
    scanf("%d%d%d", &n, &m, &mod);
    for(int i = 1; i <= n; i ++)    scanf("%d", &a), f[a] ++;
    g[1] = 1; int M = m;
    while(m) {
        if(m % 2) {
            for(int i = 1; i < mod; i ++)    fz[i] = 0;
            for(int i = 1; i < mod; i ++)
                for(int j = 1; j < mod; j ++)
                    fz[i * j % mod] = (fz[i * j % mod] + 1ll * g[i] * f[j]) % MOD;
            for(int i = 1; i < mod; i ++)    g[i] = fz[i];
        }
        for(int i = 1; i < mod; i ++)    fz[i] = 0;
        for(int i = 1; i < mod; i ++)
            for(int j = 1; j < mod; j ++)
                fz[i * j % mod] = (fz[i * j % mod] + 1ll * f[i] * f[j]) % MOD;
        for(int i = 1; i < mod; i ++)    f[i] = fz[i];
        m >>= 1;
    }
    LL ans = 0;
    for(int i = 1; i <= mod; i ++)    ans = (ans + 1ll * g[i] * i) % MOD;
    ans = ans * mpow(mpow(n, M), MOD - 2) % MOD;
    printf("%lld", ans);
    return 0;
}

Solution

完全没想到是带权并查集!!

网上大佬讲解的很好!写的时候细节也比较多,对带权并查集理解深了一层了QAQ想不通的一点就是排序如果按二维排就会错一个点??

Code

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

inline LL read() {
    LL x = 0;    int t = 0;    char ch = getchar();
    while(!isdigit(ch))    t |= (ch == '-'), ch = getchar();
    while(isdigit(ch))    x = x * 10 + ch - '0', ch = getchar();
    return x * (t ? -1 : 1);
}

struct Node {
    int x, y; LL w;
} a[100005];
bool cmp1(Node a, Node b) { return a.x < b.x; }
bool cmp2(Node a, Node b) { return a.y < b.y; }

LL fx[100005], fy[100005], wx[100005], wy[100005];
int findx(int x) {
    if(fx[x] == x)    return fx[x];
    int hx = findx(fx[x]);
    wx[x] += wx[fx[x]];
    return fx[x] = hx;
}

bool checkx(int x, int y, LL w) {
    int hx = findx(x), hy = findx(y);
    if(hx == hy)    return wx[x] == wx[y] + w;
    fx[hx] = hy;    wx[hx] = wx[y] + w - wx[x];
    return 1;
}

int findy(int x) {
    if(fy[x] == x)    return fy[x];
    int hy = findy(fy[x]);
    wy[x] += wy[fy[x]];
    return fy[x] = hy;
}

bool checky(int x, int y, LL w) {
    int hx = findy(x), hy = findy(y);
    if(hx == hy)    return wy[x] == wy[y] + w;
    fy[hx] = hy;    wy[hx] = wy[y] + w - wy[x];
    return 1;
}

int R, C, n;
LL Min[100005], Max[100005];
bool work() {
    R = read(), C = read();
    n = read();
    memset(Min, 127, sizeof(Min));
    memset(Max, 127, sizeof(Max));
    int p = 1;
    for(int i = 1; i <= n; i ++) {
        a[i].x = read(), a[i].y = read(), a[i].w = read();
        if(a[i].w < 0 || (R * C <= 12 && a[i].w >= 3 && R != 1))    p = 0;
    }
    if(!p)    return 0;
    for(int i = 1; i <= R; i ++)    fx[i] = i, wx[i] = 0;
    for(int i = 1; i <= C; i ++)    fy[i] = i, wy[i] = 0;
    sort(a + 1, a + 1 + n, cmp1);
    for(int i = 1; i < n; i ++) {
        if(a[i].x == a[i + 1].x && !checky(a[i].y, a[i + 1].y, a[i + 1].w - a[i].w))
            return 0;
    }
    sort(a + 1, a + 1 + n, cmp2);
    for(int i = 1; i < n; i ++) {
        if(a[i].y == a[i + 1].y && !checkx(a[i].x, a[i + 1].x, a[i + 1].w - a[i].w))
            return 0;
    }
    for(int i = 1; i <= n; i ++) {
        int x = findx(a[i].x);
        Min[x] = min(Min[x], a[i].w + wx[a[i].x]);
    }
    for(int i = 1; i <= R; i ++) {
        int x = findx(i);
        Max[x] = min(Max[x], -wx[i]);
    }
    for(int i = 1; i <= R; i ++) {
        if(Min[i] + Max[i] < 0 && fx[i] == i)    return 0;
    }
    return 1;
}

int main() {
    freopen("then.in", "r", stdin);
    freopen("then.out", "w", stdout);
    int T;
    scanf("%d", &T);
    while(T --) {
        if(work())    puts("Yes");
        else        puts("No");
    }
    return 0;
}

Solution

乍一看怎么那么像聪聪与可可??然而这实际上是面具下隐藏着的小模拟!!!QAQ

仔细读读题发现自己的移动根本是没有用的,因为这一步除了使距离拉近一步外什么都没有做,不如给自己回蓝或者尽量去打香港记者,因为此时的距离的贡献一定比以后优。

然后就是能打就打,不能打就回蓝。

香港记者走的永远是受伤害最小的地方,因此要比较三个方位,然而就是这里让100分打水漂了QAQ

因为在最后他也可以只走一步,不一定一定要走两步,所以下面的写法就很精髓了QAQ

 

for(int i = 1; i <= 2; i++) {
	if(tx == 0 && ty == 0)	break;
	if(tx <= ty)	ty--;
	else tx--;	
}

 

Code

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

inline int read() {
    int x = 0;    int t = 0;    char ch = getchar();
    while(!isdigit(ch))    t |= (ch == '-'), ch = getchar();
    while(isdigit(ch))    x = x * 10 + ch - '0', ch = getchar();
    return x * (t ? -1 : 1);
}

int a, b;
int a1, a2, b1, b2, c, d;

inline LL Min(LL a, LL b) {
    return a < b ? a : b;
}

void work() {
    a1 = read(), b1 = read(), a2 = read(), b2 = read(), c = read(), d = read();
    int tx = abs(a1 - a2), ty = abs(b1 - b2);
    int flag = 1;
    while(1) {
        if(d <= 0)    break;
        if(tx == 0 && ty == 0) { flag = 0;    break; }
        if(c < a)    c += b;
        else    c -= a, d -= tx * tx + ty * ty;
        if(d <= 0)    break;
        for(int i = 1; i <= 2; i++) {
            if(tx == 0 && ty == 0)    break;
            if(tx <= ty)    ty--;
            else tx--;    
        }
    }
    if(flag)    printf("NAIVE\n");
    else        printf("SIMPLE\n");
}

int main() {
    freopen("do.in", "r", stdin);
    freopen("do.out", "w", stdout);
    int T;
    T = read();
    a = read(), b = read();
    while(T --) {
        work();
    }
    return 0;
}

 

posted @ 2018-11-01 19:23  Wans_ovo  阅读(155)  评论(0编辑  收藏  举报