组队赛4 - 2014.8.3 - 2013成都现场赛

本文探讨了构建具有特定属性的图以及从给定区间内等概率选择数进行概率计算的方法。具体包括构造满足一定条件的图,以及计算在特定条件下两数相加对模运算结果的概率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

hdu-4781-Assignment For Princess

problem

1.让你构造一个图,下面是这个图的样子。

2.n个点m条边,每条边是有向边,权值是[1, m],任意两个边的权值都不一样。n[10, 80], m[n+3, n^2/7]

3.没有子环,任两个点之间最多有一条边(这句话的意思是,两个点之间直接相连的边,最多只有一条,不同方向的也算两条)。

4.任意两个点之间都是可以到的。

5.每个点出发,都可以回到这个点,并且每个一圈的权值和是3的倍数。

think

1.先把1到n做成一个圈,这样用了n个点。其中前几个边的权值是1-(n-1), 最后一个点是n或n+2,为了满足一圈的和是%3==0嘛。

2.这样任意两个点之间都有了唯一的距离,加权值为k的边的时候,只要dis[i][j] % 3 == k % 3就可以加上去了。

code

int dis[90][90];
int has[90][90];
int vis[1000];
int val[90];

int a[1000], b[1000], c[1000];
int cnt;

bool solve(int n, int m){
    memset(vis, 0, sizeof(vis));
    memset(has, 0, sizeof(has));
    int x;
    if(n % 3 == 1) x = n + 2;
    else x = n;
    for(int i = 1; i < n; ++i){
        vis[i] = 1;
        val[i] = i;
    }
    vis[x] = 1;
    val[n] = x;
    for(int i = 1; i <= n; ++i){
        int ii = i + 1;
        if(ii > n) ii = 1;
        a[++cnt] = i;
        b[cnt] = ii;
        c[cnt] = val[i];
        has[i][i] = 1;
        has[i][ii] = 1;
        has[ii][i] = 1;

        for(int j = 1; j <= n; ++j){
            if(i == j) dis[i][j] = 0;
            else if(i < j) dis[i][j] = (dis[i][j-1] + val[j-1]) % 3;
            else dis[i][j] = (3 - dis[j][i]) % 3;
        }
    }
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= n; ++j){
            if(has[i][j] || has[j][i]) continue;
            for(int k = 1; k <= m; ++k){//这里可以优化为O(1),但是n和m这么小不需要优化也能过
                if(!vis[k] && (k % 3 == dis[i][j])){
                    a[++cnt] = i;
                    b[cnt] = j;
                    c[cnt] = k;
                    vis[k] = 1;
                    has[i][j] = 1;
                    has[j][i] = 1;
                    break;
                }
            }
        }
    }
    for(int i = 1; i <= m; ++i){
        if(vis[i] == 0) return false;
    }
    return true;
}

int main(){
    int T, tt = 0;
    scanf("%d", &T);
    while(T--){
        int n, m;
        cin >> n >> m;
        printf("Case #%d:\n", ++tt);
        cnt = 0;
        if(solve(n, m)){
            for(int i = 1; i <= m; ++i) printf("%d %d %d\n", a[i], b[i], c[i]);
        } else {
            puts("-1");
        }
    }
    return 0;
}

hdu-4790-Just Random

problem

从区间[a, b]等概率选择一个数x,从区间[c, d]等概率选择一个数y,

问 (x+y) % p == m 的概率是什么。

给你a, b, c, d, p, m范围都是1e9

think

看有多少个(x+y) % p == m 的(x, y) 点对。结果除以(b - a + 1) * (d - c + 1)

可以把x和y看作坐标上面的两维。那么我们求的就是x + y == m, x + y == p + m , …… x + y == k*p + m 这些线段上面有多少个点。

我们可以求出x固定时,有多少个满足要求的y。

然后再求一求吧。

首先我们求的区间是左端是0的比较容易吧。于是我们定义一个函数,solve(a, b)表示第一维区间是[0, a], 第二维区间是[0, b]时满足条件的(x, y)点对数。

于是结果就是solve(b, d) - solve(b, c-1) - solve(a-1, d) + solve(a-1, c-1)

然后solve(a, b)这个函数。每个人有每个人不同的求法吧。我总觉得我的求法有点麻烦。。。

首先我们得到,这些线段们与y轴的交点个数。就是当x==0时。设这个数是n.

然后得到当y==b时,最小的x。设这个数为x。

讨论x的情况。

如果x<=m的话,就是在[x, m] 这个区间,会比别处多一个。加上就好。但是x==0的话,就把n减一再加。

如果x==m+1的话,就是在各处都是n。

如果x>m+1的话,就是在[x+1, m-1]比别处少一个。减去就好。

详见代码。

code

LL m, p;

LL solve(LL a, LL b){
    if(a < 0 || b < 0) return 0;
    LL n;
    if(b >= m) n = (b - m) / p + 1;
    else n = 0;
    LL x;
    if(m >= b) x = (m - b) % p;
    else x = (m - b + (b - m) * p) % p;
    LL ans = 0;
    if(x == 0) --n;
    ans += n*(a+1);

    if(x <= m){
        LL k = a / p;
        ans += k*(m-x+1);
        ans += min(a, k*p + m) - min(a, k*p + x - 1);
    }
    else if(x > m+1){
        LL k = a / p;
        ans -= k * (x - m - 1);
        ans -= min(a, k*p + x - 1) - min(a, k*p + m + 1 - 1);
    }
    return ans;
}

int main(){
    int T, tt = 0;
    LL a, b, c, d;
    scanf("%d", &T);
    while(T--){
        scanf("%I64d%I64d%I64d%I64d%I64d%I64d", &a, &b, &c, &d, &p, &m);
        LL ans = solve(b, d) - solve(b, c-1) - solve(a-1, d) + solve(a-1, c-1);
        LL sum = (b - a + 1) * (d - c + 1);
        LL gg = __gcd(sum, ans);
        ans /= gg;
        sum /= gg;
        printf("Case #%d: %I64d/%I64d\n", ++tt, ans, sum);

    }
    return 0;
}
/*
33333
0 5 0 5 3 0
0 999999 0 999999 1000000 0
0 3 0 3 8 7
3 3 4 4 7 0
0 5 0 0 3 1
0 5 0 1 3 1
0 5 0 2 3 1
0 5 0 3 3 1
0 5 0 4 3 1
0 5 0 5 3 1
0 5 0 6 3 1
0 5 0 7 3 1
0 5 0 8 3 1
*/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值