2021/01/26补题(1600+1300)

Lonely Numbers (CodeForces - 1423K )

题意

首先给出一个定义:若两个数a,b满足以gcd(a,b),a/gcd(a,b),b/gcd(a,b)的值为边长的三条边能够组成一个三角形,则称a,b为友好数。先给出一个正整数n,问从1~n中有多少个数无法与给出的其他数字组成友好数

思路

借鉴dalao的思路: 点击跳转

一、如果一个数为质数,那么这个质数的友好数只有可能是它的平方
证明:设一个质数x的友好数为y
①当(y%x!=0)时,三条边长度分别为1,x,y,最短边为1,只有当x== y时才能组成三角形,显然不成立
②当(y%x == 0 && y/x=k)时,三条边长度分别为x,1,k,与①同理,只有当x==k是才能组成三角形,此时y=x*x

二、如果一个数为合数,那么这个数一定可以在比它小的数中找到友好数
证明:设一个合数x的友好数为y
①若x为某质数的平方,则可由(一)证
②若x不为质数的平方,可将其分解为x=ab (其中a<=b),那么取y=a(b-1),那么x与y可产生三条边a,b,b-1,因为合数的因数a与b满足 a>=b>1 ,所以这三条边一定可以组成一个三角形

那么我们只需要统计1~n中出现的特定质数(该质数的平方<n)的个数,运用欧拉筛与差分即可

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 5;

int prime[N], ans[N];
bool st[N];

int main() {
	int k = 0;
	for (int i = 2; i <= N; i++) {
        if (!st[i])
            prime[++k] = i;
            for (int j = 1; prime[j] <= N / i; j++) {
            	st[prime[j] * i] = true;
                if (i % prime[j] == 0)
                    break;
            }
    }
    for (int i = 1; i <= k; i++) {
    	if (prime[i] <= 1000)
    		ans[prime[i] * prime[i]]--;
    	ans[prime[i]]++;
	}
	ans[1] = 1;
	for (int i = 2; i < N; i++) 
		ans[i] += ans[i - 1];
	int t;
	scanf("%d", &t);
	while (t--) {
		int n;
		scanf("%d", &n);
		printf("%d\n", ans[n]);
	}
	return 0;
}

Nice Matrix (CodeForces - 1422B )

题意

给出一个n*m的矩阵,给矩阵中每个元素加上或减去某个值,使其变为一个回文矩阵(每一个元素对应的行与列都是回文串),求这些值的绝对值总和最少可以为多少

思路

找出该元素分别对应行与列中的对称位置的两个元素,然后找出这三个元素的中位数,将另外两个数变为这个中位数,将变化的值累加就是最优解

代码

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 105;

LL g[N][N];

void solve() {
	LL n, m, ans = 0;
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; i++) 
		for (int j = 1; j <= m; j++) 
			scanf("%lld", &g[i][j]);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++) {
			vector<int> t;
			t.push_back(g[i][j]);
			t.push_back(g[i][m - j + 1]);
			t.push_back(g[n - i + 1][j]);
			sort(t.begin(), t.end());
			g[i][j] = g[i][m - j + 1] = g[n - i + 1][j] = t[1];
			ans += (t[1] - t[0] + t[2] - t[1]);
		}
	printf("%lld\n", ans);
}

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		solve();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值