(6/6) Codeforces Round #694 (Div. 2)

(6/6) Codeforces Round #694 (Div. 2)

A. Strange Partition

题意:

给一个数组,数组中的所有元素可以任意合并,求数组的每个元素除以x上去整的和,求结果的最大值和最小值。

思路:

瞎猜。最小值肯定是都合并在一起,最大值是分开。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int a[100010];

void work() {
	int n, x;
	cin >> n >> x;
	int s1 = 0, s2 = 0;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		s1 += a[i];
		s2 += (a[i] + x - 1) / x;
	}
	cout << (s1 + x - 1) / x << " " << s2 << endl;
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int cas;
	cin >> cas;
	while (cas--) work();
	return 0;
}

B. Strange List

题意:

给你一数组,一个x,从前往后遍历数组(也会遍历后面加进来的元素),如果当前元素a可以被x除尽,则在数组末尾加上x个a/x。如果不能被除尽则停止,问数组的元素之和。

思路:

可以很显然看出一个性质如果a/x也能被x除尽,那么结果增加a,因为一共有x个a/x。
模拟,如果能除尽,则结果加上当前元素,不能除尽则跳出。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int a[100010];
int b[100010];

void work() {
	int n, x, s = 0;
	cin >> n >> x;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
		b[i] = a[i];
		s += a[i];
	}
	for (int i = 0; i < n; i = (i + 1) % n) {
		if (b[i] % x == 0) s += a[i], b[i] = b[i] / x;
		else break;
	}
	cout << s << endl;
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int cas;
	cin >> cas;
	while (cas--) work();
	return 0;
}

C. Strange Birthday Party

题意:

商品按价钱从小到大排序,每个商品只能拿1次。
n个客人,每个客人有一个权值,只能拿下标比权值小的商品或者给客人下标为权值的商品对应的现金。

思路:

排序贪心,权值大的先拿前面的,序号小的后拿,如果不存在了,就拿现金。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
#define int long long
constexpr int N = 300010;
int k[N],c[N],vis[N];

void work() {
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>k[i];
	for(int i=1;i<=m;i++) vis[i] = 0;
	for(int i=1;i<=m;i++) cin>>c[i];
	sort(k+1,k+1+n);
	int ans = 0;
	int j = 1;
	for(int i=n;i>=1;i--){
		if(c[k[i]]>c[j] && !vis[j] && j<=m){
			ans+=c[j];
			vis[j] = 1;
			j++;
		}else{
			ans+=c[k[i]];
		}
	}
	cout<<ans<<endl;
}
 
int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--) work();
    return 0;
}

D. Strange Definition

题意:

如果 l c m ( x , y ) / g c d ( x , y ) lcm(x,y)/gcd(x,y) lcm(x,y)/gcd(x,y)为一个完全平方数,那么x和y相邻。给你一个数组,从0秒开始,每秒钟每个元素都会被其和与其互为完全平方数的乘积替换,设 d i d_i di为数组中第i个元素共有几个互为完全平方数的数(包含本身)。
q个询问,每个询问询问第i秒时d的最大值。

思路:

有一个明显的推理:x*y如果是完全平方数,那么x和y相邻。
那么我们把所有元素的偶数质因子都筛掉,设为core数组,那么如果core[x]=core[y],那么x和y相邻。
当询问为0,我们只需要输出出现次数最多的core。
当询问不为0,比如为1,那么core出现为偶数次的下次都会为1,如果出现奇数次下次不变,特例当core为1时无论奇偶都不变。所以重新统计。
当询问大于1,我们可以推一下,结果与1相同。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
int primes[1001000];

void work() {
	unordered_map<int, int> haxh;
	int n;
	cin >> n;
	haxh[1] = 0;
	for (int i = 1; i <= n; i++) {
		int h = 1, x;
		cin >> x;
		while (primes[x] != 1) {
			int t = 0;
			int j = primes[x];
			while (x % j == 0) {
				x /= j;
				t++;
			}
			if (t % 2) h *= j;
		}
		haxh[h]++;
	}

	int cnt1 = 0, cnt2 = 0;
	for (auto i : haxh) cnt1 = max(cnt1, i.second);
	
	for (auto &i : haxh) 
		if (i.first != 1 && i.second % 2 == 0) {
			haxh[1] += i.second;
			i.second = 0;
		}
	
	for (auto i : haxh) cnt2 = max(cnt2, i.second);
		
	int q;
	cin >> q;
	while (q--) {
		int x;
		cin >> x;
		if (x == 0) cout << cnt1 << endl;
		else cout << cnt2 << endl;
	}
}

int32_t main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	primes[1] = 1;
	for (int i = 2; i <= 1000100; i++) {
		if (!primes[i]) {
			primes[i] = i;
			for (int j = i * 2; j <= 1000100; j += i) 
				if (!primes[j]) primes[j] = i;
		}
	}
	int cas;
	cin >> cas;
	while (cas--) work();
}

E. Strange Shuffle

题意:

交互题,一组人围成一圈,每个人都会把当前元素/2下取整给左侧的人,当前元素/2上取整给右侧的人。
每秒所有人同时执行该操作一次。
有一个伪装者,他会把所有的元素都给右侧,要求在1000秒内找出伪装者,每秒可以进行一次询问,询问q位置的人的当前元素。

思路:

打表看规律。n为15,p为5,下标从1开始,k为50,第一行为初始状态。

每多一秒,会多出现一个大于k的数, s q r t ( 100000 ) = 330 sqrt(100000)=330 sqrt(100000)=330,我们先用sqrt次,让其出现sqrt个大于k的数,我们可以发现,答案位置永远为k,答案右侧大于k,答案左侧小于k。
所以我们找到一个大于k或者小于k的数,然后左移或者右移到第一个等于k的数,即为所求。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
#define x first
#define y second
#define bg begin()
#define ed end()
#define pb push_back
#define mp make_pair
#define sz(a) int((a).size())
#define R(i,n) for(int i(0);i<(n);++i)
#define L(i,n) for(int i((n)-1);i>=0;--i)
const int iinf=0x3f3f3f3f;
const ll linf=0x3f3f3f3f3f3f3f3f;
 
const int N=3e5;
int n,m,a[N],b[N];
 
int ask(int i){
    cout<<"? "<<i+1<<endl;
    int x; cin>>x; return x;
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m;
    const int B=sqrt(n)-1;
    R(i,B+1) ask(i);
    int p=0,x=ask(p);
    while(x==m) (p+=B)%=n,x=ask(p);
    if(x>m){ 
        while(ask((p+n-B)%n)>m) (p+=n-B)%=n;
        while(ask((p+n-1)%n)>m) (p+=n-1)%=n;
        (p+=n-1)%=n;
    } else { 
        while(ask((p+B)%n)<m) (p+=B)%=n;
        while(ask((p+1)%n)<m) (p+=1)%=n;
        ++p%=n;
    }
    cout<<"! "<<p+1<<endl;
    return 0;
}

F. Strange Housing

题意:

给你节点和边,染色,染色的住老师,未染色的住学生。
要求:相邻的节点不能同时染色,只有染色的节点和不染色的节点相邻的边才成立,要求图联通。

思路:

暴力贪心即可。如果与当前节点相邻的所有节点没老师,那当前节点就放老师,否则不放。
如果有节点未遍历到,则输出NO。
证明:老师一定不相邻,一定联通,放学生时周围一定有老师。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 300010;
vector<int> g[maxn];
int cnt;
int st[maxn];

void dfs(int u) {
	int sum1 = 0, sum2 = 0;
	
	for (int i = 0; i < g[u].size(); i++) 
		if (st[g[u][i]]) {
			if (st[g[u][i]] == 1) sum1++;
			else sum2++;
			// cout << st[g[u][i]] << endl;
			// cout << "---" << endl;
		}
	// cout << sum1 << endl;
	if (sum1 == 0) st[u] = 1;
	else st[u] = 2;
	
	for (int i = 0; i < g[u].size(); i++) 
		if (!st[g[u][i]]) dfs(g[u][i]);
}

void work() {
	cnt = 0;
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++) st[i] = 0, g[i].clear();
	while (m--) {
		int a, b;
		cin >> a >> b;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	
	dfs(1);
	
	int cnt = 0, flag = 0;
	for (int i = 1; i <= n; i++) {
		if (st[i] == 1) cnt++;
		if (!st[i]) flag = 1;
	}
	
	if (flag) cout << "NO" << endl;
	else {
		cout << "YES" << endl;
		cout << cnt << endl;
		for (int i = 1; i <= n; i++)
			if (st[i] == 1) cout << i << " ";
			cout << endl;
	} 
	
}

int32_t main() {
	int cas;
	cin >> cas;
	while (cas--) work();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值