Codeforces Round #697 (Div. 3)

本文解析了一场编程比赛中的六道题目,并提供了相应的代码实现。涵盖了从简单到复杂的各种类型问题,如判断整数属性、计算组合数以及矩阵操作等。

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

比赛传送门
看到unrated直接睡觉去了(手动狗头) ,又错失一次 上分 掉分好时机QAQ。

A. Odd Divisor

题意:

判断整数n有没有奇数因子(odd divisor)。

思路:

签到题

Code:

int main() {
	int t;
	cin >> t;
	while (t--) {
		LL n;
		cin >> n;
		while (n % 2 == 0) {
			n /= 2;
		}
		if (n == 1) cout << "NO" << endl;
		else cout << "YES" << endl;
	} 
	return 0;
}

B. New Year’s Number

题意:

判断整数n是否可以写出x*2020+y*2021的形式。

思路:

看n除以2020的余数 乘以2021会不会超过n。若超过n则不可以,反之则可以。

Code:

int main() {
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		if ((n%2020)*2021 <= n) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

C. Ball in Berland

题意:

一个男生和一个女生配成一对,总共有k对,求选两对男女同台演出的方案数。

思路:

假设有两对,分别为(x1,y1),(x2,y2)。那么要保证x1 != x2 && y1 != y2。
首先不考虑能不能同台表演,总的方案数应该是C(k,2)。
比如说这里的男1,他可以分别和女234配对,但很明显所组成的三个对每次选择只能在三个中选一个,也就是说对于答案而言,损失了2+1=3个方案,。女2,女4同理。img1
所以,最终的答案应该是C(k,2)- Σq。其中q为 0+···+(a[i]-1)。

Code:

int a[200005], b[200005];
map<int, int> A;
map<int, int> B;
ll sum(int n) {
	return 1ll*(1+n)*n/2;
}
int main() {
	int t;
	read(t);
	while (t--) {
		int n, m, k;
		read(n), read(m), read(k);
		A.clear(), B.clear(); 
		for (int i = 0; i < k; i++) {
			read(a[i]);
			A[a[i]]++;
		}
		for (int i = 0; i < k; i++) {
			read(b[i]);
			B[b[i]]++;
		}
		ll ans = k*1ll*(k-1)/2;
		for (int i = 0; i < k; i++) {
			if (A[a[i]]>1) ans -= sum(A[a[i]]-1), A[a[i]] = 0;
			if (B[b[i]]>1) ans -= sum(B[b[i]]-1), B[b[i]] = 0;
		}	
		cout << ans << endl;
	}
}

D. Cleaning the Phone

题意:

手机有n个应用程序,第i个应用占ai个单位的内存,便利点(convenience points)为bi。现在要清理出至少m个单位的内存空间,要求损失最少的便利点。

思路:

便利点只有1和2,首先把便利点为1的和2的分开来存,按递减排序,然后枚举便利点为 1的数组,取其前i个数,对于每种情况,在便利点为2的前缀和中二分找剩余内存的对应的下标,1i+2pos即为该情况下的最优解,最后取最小值更新答案。

Code:

int main() {
	int t;
	cin >> t;
	while (t--) {
		int n, m, ia = 1, ib = 1;
		LL sum = 0;
		cin >> n >> m;
		for (int i = 0; i < n; i++) {
			cin >> tmp[i];
			sum += tmp[i];			
		}
		for (int i = 0; i < n; i++) {
			LL x;
			cin >> x;
			if (x == 1) a[ia++] = tmp[i];
			else b[ib++] = tmp[i];
		}
		if (sum < m) {
			cout << -1 << endl;
			continue;
		}
		sort(a+1, a+ia, cmp);
		sort(b+1, b+ib, cmp);
		for (int i = 1; i < ib; i++) {
			sumb[i] = sumb[i-1] + b[i];
		}
		LL ans = INF, cnt = 0;
		for (int i = 0; i < ia; i++) {
			cnt += a[i];
			if (cnt >= m) {
				ans = min(ans, 1LL*i);
				break;
			}
			int dt = m - cnt;
			int pos = lower_bound(sumb+1, sumb+ib, dt) - sumb;
			if (pos == ib) continue;
			ans = min(ans, 1LL*i+2*pos);
		}
		int pos = lower_bound(sumb+1, sumb+ib, m) - sumb;
		if (pos != ib)
			ans = min(ans, 2LL*pos);
		cout << ans << endl;
	}
	return 0;
}

E. Advertising Agency

题意:

总共有n个人,第i个人对应权值ai。在n个人中雇k个,使得权值最大,求方案数。

思路:

假设8个人中选5个,出现这种情况:

4 3 3 2 2 2 2 1

理解题意可知,以上例子中,重复的3不需要考虑,而重复的2恰好位于选与不选之间,所以就会有多种方案(事实上4 3 3 2 2存在6种情况)。j设a为2的总数,b为需要选2的个数,很容易推出,其实答案是C(a,b),对答案取模1e9+7。可以用拓展欧几里得,边求组合数边取模。

Code:

const int mod = 1e9+7;
int a[1005];
int cmp(int a, int b) {
	return a > b;
}
const int maxn = 1005;
LL fac[maxn];
LL ex_gcd(LL a,LL b,LL &x,LL &y){
    if(b==0){x = 1;y = 0;return a;}
    LL ans = ex_gcd(b,a%b,x,y);
    LL temp = x;
    x = y;
    y = temp - (a/b)*y;
    return ans;
}
LL inv(LL a){
    LL x,y;
    int ans = ex_gcd(a,mod,x,y);
    if(ans!=1)return -1;
    if(x<0)x = (x%mod+mod)%mod;
    return x;
}
void solve(){
    fac[0] = 1;
    for(int i = 1;i<=maxn-1;i++){
        fac[i] = (fac[i-1]*i)%mod;
    }
}
LL comb(int n,int k){
    if(k>n)return 0;
    return (fac[n]*inv(fac[k])%mod*inv(fac[n-k])%mod)%mod;
}
int main() {
	int t;
	solve();
	read(t);
	while (t--) {
		int n, k;
		read(n), read(k);
		for (int i = 1; i <= n; i++) read(a[i]);
		sort(a+1, a+1+n, cmp);
		int sum = 0, pos = -1;
		for (int i = 1; i <= n; i++) {
			if (pos == -1 && a[i] == a[k]) pos = i;
			if (a[i] == a[k]) sum++;
			if (a[i]<a[k]) break;
		}
		int sel = k-pos+1;
		cout << comb(sum, sel) << endl;
	}
	return 0;
}

F. Unusual Matrix

题意:

给你一个初始二进制矩阵,问你经过操作:

1.对行异或;
2.对列异或

能不能转换成目标矩阵。

思路:

先预处理:找出初始矩阵与目标矩阵有差异的地方,一样的地方用0表示,不一样的用1表示。有差异那就说明:这个点一定是要经过转换的,而转换偶数次是没有意义的,只能转换奇数次。
对于点(x,y)来说,如果要转换它,就意味着要连带转换(1,y)或(x,1)这个点,而(1,y)、(x,1)又可以通过改变(1,1)变回来,所以,如果这四个点全相同或者有两个不同,就可以完成转换,反之,则不可。

Code:

string s;
int mp[1005][1005];
int main() {
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		for (int i = 1; i <= n; i++) {
			cin >> s;
			for (int j = 0; j < n; j++)
				mp[i][j+1] = s[j]-'0';
		}
		for (int i = 1; i <= n; i++) {
			cin >> s;
			for (int j = 0; j < n; j++)
				mp[i][j+1] ^= s[j]-'0';
		}
		int flag = 0;
		for (int i = 2; i <= n; i++) {
			for (int j = 2; j <= n; j++) {
				if (mp[1][j]^mp[i][1]^mp[1][1]^mp[i][j]) {
					flag = 1;
					break;
				}
			}
		}
		if (flag) puts("NO");
		else puts("YES");
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liudashuai666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值