2017 Multi-University Training Contest - Team 4

本文精选了四道算法竞赛题目并提供了详细的解题思路及代码实现,包括因子个数求和、二分图完全匹配、求模运算以及图像时间识别等。

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

1003

题意:d(i)为i的因子的个数,求区间[l, r] 所有d(i)     l<=i <=r  的和

因子个数求法:传送门

思路:这样直接去求还是会TLE,所以我们用类似素数筛法进行区间筛来减少计算次数

每次在区间内找到第一个能整除素数p的,假设这个数是x,那么x + p 也是可以整除p的。就是普通的线性筛类似

#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)    memset(a, b, sizeof a)
#define REP(i, x, n)    for(int i = x; i <= n; ++i)
const int qq = 5e6 + 10;
const LL MOD = 998244353;
LL prime[qq], tot = 0;
bool ispirme[qq];
LL l, r, k;
LL num[qq], ans[qq];
void Init() {
    for(int i = 2; i < qq; ++i) {
        if(!ispirme[i]) {
            prime[++tot] = i;
        }
        for(int j = 1; j <= tot && (LL)i * prime[j] < qq; ++j) {
            ispirme[(LL)i * prime[j]] = true;
            if(i % prime[j] == 0)    break;
        }
    }
//    printf("QQQ\n");
}

int main(){
    Init();
    int t;    scanf("%d", &t);
    while(t--) {
        scanf("%lld%lld%lld", &l, &r, &k);
        for(LL i = l; i <= r; ++i) {
            num[i - l] = i;
            ans[i - l] = 1;
        }
//        printf("QQQ\n");
        for(LL i = 1; i <= tot; ++i) {
            LL j = (l + prime[i] - 1LL) / prime[i] * prime[i];
//            printf("%lld\n", j);
//            if(r < prime[i])    break;
            while(j <= r) {
                LL p = 0;
                while(num[j - l] % prime[i] == 0) {
                    p++;
                    num[j - l] /= prime[i];
                }
                ans[j - l] = (ans[j - l] * (p * k + 1LL));
                if(ans[j - l] >= MOD)    ans[j - l] %= MOD;
                j = j + prime[i];
//                printf("%lld\n", j);
            }
        }
        LL sum = 0;
        for(LL i = l; i <= r; ++i) {
            if(num[i - l] != 1)    sum = sum + ans[i - l] * (k + 1LL);
            else    sum = sum + ans[i - l];
            if(sum >= MOD)    sum %= MOD;
        }
        printf("%lld\n", sum);
    }
    return 0;
}



1007

题意:给定二分图,求出图中所有完全匹配图的边权乘积的和,保证至少有一种完全匹配

思路:参考这位聚聚的代码 传送门

e[i] = e[i ^ 1] = 1 是标记了边。之前在想标记点为什么不行后来比对了两份标记边和点的代码发现

标记点访问顺序:8 16 9 18

标记边的访问顺序:8 16 9 18 8

感觉做一下处理标记点也是可以的,不过好像比较麻烦

#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)	memset(a, b, sizeof a)
#define REP(i, x, n)	for(int i = x; i <= n; ++i)
const int qq = 300000 + 10;
const int MOD = 998244353;
struct Edge {
	int nxt, to, w;
	bool mrk;
}e[qq << 2];
int T, n, head[qq << 1], cnt, deg[qq << 1], used[qq << 1];
LL part[2];
void Init() {
	mst(head, -1);
	mst(deg, 0);
	mst(used, 0);
	cnt = 0;
}
void AddEdge(int u, int v, int w) {
	e[cnt].nxt = head[u];
	e[cnt].to = v;
	e[cnt].w = w;
	e[cnt].mrk = 0;
	head[u] = cnt++;
}
void Dfs(int cur, int idx) {
	printf("%d ", cur);
	used[cur] = 1;
	for(int i = head[cur]; i != -1; i = e[i].nxt) {
		if(e[i].mrk)	continue;
		e[i].mrk = e[i ^ 1].mrk = 1;
		(part[idx] *= e[i].w) %= MOD;
		Dfs(e[i].to, 1 - idx);
	}
}

int main(){
	scanf("%d", &T);
	while(T--) {
		scanf("%d", &n);
		Init();
		for(int u = 1, v, w; u <= n; ++u) {
			for(int j = 0; j < 2; ++j) {
				scanf("%d%d", &v, &w);
				AddEdge(u, v + n, w);
				AddEdge(v + n, u, w);
				deg[u]++, deg[v + n]++;
			}
		}
		LL ans = 1;
		queue<int> Q;
		for(int v = n + 1; v <= n + n; ++v) {
			if(deg[v] == 1) {
				Q.push(v);
			}
		}
		while(!Q.empty()) {
			int v = Q.front();
			Q.pop();
			used[v] = 1;
			for(int i = head[v]; i != -1; i = e[i].nxt) {
				if(e[i].mrk)	continue;
				e[i].mrk = e[i ^ 1].mrk = 1;
				used[e[i].to] = 1;
				(ans *= e[i].w) %= MOD;
				for(int j = head[e[i].to]; j != -1; j = e[j].nxt) {
					e[j].mrk = e[j ^ 1].mrk = 1;
					deg[e[j].to]--;
					if(deg[e[j].to] == 1)	Q.push(e[j].to);
				}
			}
		}
		printf("%lld\n", ans);
		for(int u = 1; u <= n; ++u) {
			if(used[u])	continue;
			part[0] = part[1] = 1;
			Dfs(u, 0);
			puts("");
			printf("%lld %lld\n", part[0], part[1]);
			(ans *= (part[0] + part[1]) % MOD) %= MOD;
		}
		printf("%lld\n", ans);
	}
	return 0;
}




1009

题意:给出n个数字,要你求m k,要求给出的n个数%m = k 的数字的个数要大于一半

思路:固定m = 2, 那么k只有两种情况0和1统计下等于1和等于0的情况,谁多k就是那个

#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)    memset(a, b, sizeof a)
#define REP(i, x, n)    for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
const int MOD = 1e9 + 7;
int num[qq];

int main(){
    int t;    scanf("%d", &t);
    while(t--) {
        int n;    scanf("%d", &n);
        int a, b;
        a = b = 0;
        for(int x, i = 0; i < n; ++i) {
            scanf("%d", &x);
            if(x % 2 == 0)    a++;
            else    b++;
        }
        if(a > b)    puts("2 0");
        else    puts("2 1");
    }
    return 0;
}





1011

题意:给出图像要你判断时间是多少

思路:观察每个数字缺少那一块,标记那一块,然后做一下判断

#include <cstdio>
#include <cstring>
#include <cmath>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <utility>

using namespace std;
#define LL long long
#define pb push_back
#define mk make_pair
#define pill pair<int, int>
#define ft first
#define sd second
#define mst(a, b)    memset(a, b, sizeof a)
#define REP(i, x, n)    for(int i = x; i <= n; ++i)
const int qq = 1e5 + 10;
const int MOD = 1e9 + 7;
char st[10][105], match[10][10];
bool digit[10];
int num[10][10];
int ans[10];
void Init() {
    mst(num, 0);
    num[0][4] = 1;
    num[1][1] = num[1][2] = num[1][4] = num[1][5] = num[1][7] = 1;
    num[2][2] = num[2][6] = 1;
    num[3][2] = num[3][5] = 1;
    num[4][1] = num[4][5] = num[4][7] = 1;
    num[5][3] = num[5][5] = 1;
    num[6][3] = 1;
    num[7][2] = num[7][4] = num[7][5] = num[7][7] = 1;
    num[9][5] = 1;
}

void Judge(int id) {
    for(int i = 0; i < 10; ++i)    digit[i] = false;
    if(match[1][2] == 'X' && match[1][3] == 'X') {
        digit[1] = true;
    }
    if(match[2][1] == 'X' && match[3][1] == 'X') {
        digit[2] = true;
    }
    if(match[2][4] == 'X' && match[3][4] == 'X') {
        digit[3] = true;
    }
    if(match[4][2] == 'X' && match[4][3] == 'X') {
        digit[4] = true;
    }
    if(match[5][1] == 'X' && match[6][1] == 'X') {
        digit[5] = true;
    }
    if(match[5][4] == 'X' && match[6][4] == 'X') {
        digit[6] = true;
    }
    if(match[7][2] == 'X' && match[7][3] == 'X') {
        digit[7] = true;
    }
    for(int i = 0; i < 10; ++i) {
        bool f = true;
        for(int j = 1; j <= 7; ++j) {
            int a = num[i][j];
            int b = (digit[j] == true ? 0 : 1);
            if(a != b)    f = false;
        }
        if(f){
            ans[id] = i;
            break;
        }
    }
    
}
 
int main(){
    int t;    scanf("%d", &t);
    Init();
    while(t--) {
        for(int i = 1; i <= 7; ++i) {
            scanf("%s", st[i] + 1);

        }
        int x, y;
        x = y = 0;
        for(int i = 1; i <= 7; ++i) {
            ++x;
            y = 0;
            for(int j = 1; j <= 4; ++j) {
                ++y;
                match[x][y] = st[i][j];
            }
        }
        Judge(1);
        x = y = 0;
        for(int i = 1; i <= 7; ++i) {
            ++x;
            y = 0;
            for(int j = 6; j <= 9; ++j) {
                ++y;
                match[x][y] = st[i][j];
            }
        }
        Judge(2);
        x = y = 0;
        for(int i = 1; i <= 7; ++i) {
            ++x;
            y = 0;
            for(int j = 13; j <= 17; ++j) {
                ++y;
                match[x][y] = st[i][j];
            }
        }
        Judge(3);
        x = y = 0;
        for(int i = 1; i <= 7; ++i) {
            ++x;
            y = 0;
            for(int j = 18; j <= 21; ++j) {
                ++y;
                match[x][y] = st[i][j];
            }
        }
        Judge(4);
        for(int i = 1; i <= 4; ++i) {
            printf("%d", ans[i]);
            if(i == 2)    printf(":");
        }
        puts("");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值