河北省赛HBCPC2022补题

赛时过了4道,D、H签到,F题贪心莫名卡了很久,M题用了线段树莫名过了,正解应该是用贡献度(But想不出来),赛后发现B题思路完全正确,就是没有时间写了:(,I题字符串也是一道简单dp(可惜看不出来

B_生日蛋糕

题意

对于给定的n,f[n]表示n被1到n-1整除后出现的整数种数,最后对T次询问,输出1-n的f[n]之和、

注意n可以取到1e9,结果对1e9+7取模。

思路

打表找规律,f[n] = 1,2,2,3,3,4,4,4,5,5,5,6,6,6,6……非常的明显,对于f[n],其所出现的次数就是f[n]/2+1,因为这里n非常大,没有办法直接初始化,所以可以用结构体初始化,然后再二分查找n所对应的结构体。

代码

#include <bits/stdc++.h>
using namespace std;
#define maxn 1000001
const long long mod = 1e9 + 7;

struct node {
	long long l, r;
	long long num;

} s[100001];
long long sum[100001];

void qaq() {
	for (int i = 1; i <= 100001; i++) {
		if (i == 1) {
			s[i].l = 1;
			s[i].r = 1;
			s[i].num = 1;
			sum[i] = s[i].num;
		} else {
			s[i].l = s[i - 1].r + 1;
			s[i].r = s[i].l + i / 2;
			s[i].num = i / 2 + 1;
			sum[i] = (s[i].num * i % mod + sum[i - 1] % mod) % mod;
		}
	};
}

int check(int x, long long n) {
	if (s[x].l <= n && s[x].r >= n) {
		return x;
	} else if (s[x].l > n) {
		return -1;
	} else  {
		return -2;
	}
}

int find(long long n) {
	int l = 1, r = 100001, mid = (l + r) / 2;
	int t = -3;
	while (t < 0) {
		t = check(mid, n);
		if (t == -1) { //fn在l的左边
			r = mid - 1;
		} else { //fn在r的右边
			l = mid + 1;
		}
		mid = (l + r) / 2;
	}
	return t;
}

int main() {
	int t;
	cin >> t;
	qaq();
	while (t--) {
		long long n;
		scanf("%lld", &n);
		long long ans = 0;
		int temp = find(n);
	 	ans =  (ans % mod + sum[temp - 1] % mod) % mod;
		ans =  (ans +  (temp * (n - s[temp].l + 1) ) % mod) % mod;
		printf("%lld\n", ans % mod);
	}
}

F_筷子

题意

类似于牛客多校写的那道手套题,贪心找出最亏的情况,注意结果只跟种类数与奇偶性相关。

思路

先考虑摸一双筷子的情况,答案必然为(种类数+1)。剩下的直接看代码注释。

代码

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define int long long
const int N = 1e6 + 5;
int a[N];

signed main() {
	int T;
	scanf("%lld", &T);
	while (T--) {
		LL n, m;
		scanf("%lld%lld", &n, &m);
		LL sum1 = 0, num = 0;
		for (int i = 1; i <= n; i++) {
			scanf("%lld", &a[i]);
			sum1 += a[i] / 2ll;
			if (a[i] % 2 == 1) {
				num += a[i] / 2;
			} else {
				num += a[i] / 2 - 1;
			}
		}
		if (sum1 < m) {
			printf("-1\n");
			continue;
		}
		LL ans = n + 1;
		m--;//组成一双筷子的情况: 1 1 1 1 …… 1 2
		//之后每加一双筷子就是能加2就加2,否则加1 (1 …… 1 2 3)(1 2 2)
		//在已经组成一双筷子的情况下,如果a[i]是偶数,则它可以提供的加2次数是a[i]/2-1 ,奇数则是a[i]/2
		if (num >= m) {
			ans += 2 * m;
		} else {
			ans += 2 * num + (m - num);
		}
		printf("%lld\n", ans);
	}
	return 0;
}

K_某时某地

题意

给定一个正整数 n,请分别求出对于 k=0,1,⋯,9,有多少个三元组 (x,y,z) 满足 1≤x,y,znx{YZ}k(mod10)。

思路

x^5与x 的个位数相同。

代码

待补

posted @ 2022-10-30 10:26  oddpointa  阅读(277)  评论(0)    收藏  举报