Codeforces Round #709 A - D

A - Prison Break

题意:
给定你一个 a ∗ b a*b ab的矩阵,把它看做一个监狱,然后问你最少打通多少面墙能使得一个人处于矩阵的任意一个方格内都可以逃脱。
思路:
找规律发现就是 a ∗ b a * b ab面。

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;

int main() {
	int T;scanf("%d",&T);
	while(T--) {
		int a,b;
		scanf("%d%d",&a,&b);
		printf("%d\n",a * b);
	}
	return 0;
}

B - Restore Modulo

题意:
定义 n , m ( m ≥ 0 ) , s , c ( 0 ≤ c < m ) n,m(m \geq 0),s,c(0\leq c <m) n,m(m0),s,c(0c<m)四个数,然后这四个数可以生成的一个序列 a a a,生成规则如下:
a 1 = s   m o d   m a_1 = s\ mod \ m a1=s mod m
a i + 1 = ( a i + c )   m o d   m a_{i+1} = (a_i +c )\ mod \ m ai+1=(ai+c) mod m
这样得到一个长度为 n n n的序列a
然后问你给定一个序列 a a a,能否找到符合要求的 m , c m,c m,c使得这个序列可以被生成。有唯一解输出答案,无限多解输出0,无解输出-1。
思路:
这个B感觉比C还难,但是其实注意了题目的大小条件的话也还好。

首先 n ≤ 2 n \leq 2 n2的话一定是无限多解的。
d i = a i − a i + 1 d_{i} = a_{i} - a _ {i+1} di=aiai+1 ,如果 d i d_i di都相等,那么也是无限多解。

首先 ( a i + c ) % m = a i + 1 (a_i + c)\%m = a_{i+1} (ai+c)%m=ai+1,即 a i − a i + 1 = k m + c a_i-a_{i+1} = km + c aiai+1=km+c,但是别忘了我们序列的生成过程是不断取余 m m m的并且题目规定了合法的 c c c要小于 m m m,所以这里的 k k k只能取0 或 1。
a i − a i + 1 = m + c a_i - a_{i+1} = m + c aiai+1=m+c或者 a i − a i + 1 = c a_i - a_{i+1} = c aiai+1=c,可以看到对于一组确定的 m m m c c c我们 d i d_i di序列只能最多存在两个不同的取值,大于的情况无解。

然后我们看 k m − c = d 1 km - c = d_1 kmc=d1 k m − c = d 2 km - c = d2 kmc=d2,我们知道了 0 ≤ c < m 0\leq c < m 0c<m,那么如果 d 1 / 2 < 0 d_{1/2} <0 d1/2<0,那么对应的一定有 k = 0 k = 0 k=0,假如 d 1 , d 2 d_1,d_2 d1,d2都小于0,而我们又知道 d 1 ≠ d 2 d_1 \neq d_2 d1=d2,此时 c c c无解。否则的话令 m m m = | d 1 d_1 d1 | + | d 2 d_2 d2 |, c = ∣ m i n ( d 1 , d 2 ) ∣ c = |min(d1,d2)| c=min(d1,d2),这样求出来的m和c不一定是满足要求的还要再判断求出来的 m m m是否比序列 a a a的每个数都小,这样答案才合法,这样就可以两个d都大于0的情况判掉其实。

数据范围一定注意,解题的时候别忘记

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e5 + 10;
ll a[N],d[N];
std::set<ll>ss;
int n;
//因为c要小于m a[i+1] = a[i] + c,而且a[i]也是小于m的,那么
//a[i] + c = a[i+1] + km,k = 1 或者 k = 0
int main() {
	int T;scanf("%d",&T);
	while(T--) {
		ss.clear();
		scanf("%d",&n);
		ll ma = 0;
		for(int i = 1;i <= n;i ++) {
			scanf("%d",&a[i]);
			ma = max(ma,a[i]);
		}
		if(n <= 2) {
			printf("0\n");
			continue;
		}
		for(int i = 1;i < n;i ++) {
			d[i] = a[i] - a[i+1];
			ss.insert(d[i]);
		}
		// cout << sz(ss) << '\n';
		if(sz(ss) > 2) {//最多就是 c 和 c - m两个数
			printf("-1\n");
		}
		else if(sz(ss) == 1) {
			printf("0\n");
		}
		else {
			if(*ss.begin() < 0LL && *ss.rbegin() < 0LL) {
				printf("-1\n");
			}
			else {
				ll c = abs(min(*ss.begin(),*ss.rbegin()));
				ll m = abs(*ss.begin()) + abs(*ss.rbegin());
				if(m <= ma) {
					printf("-1\n");
				}
				else printf("%lld %lld\n",m,c);
			}
		}
 	}
	return 0;
}

C - Basic Diplomacy

思路:
题目已经说明了 ∑ k ≤ 200000 \sum {k} \leq 200000 k200000,直接存个vector每天sort一下模拟过程就搞定。

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e5 + 10;
const int M = 2e5 + 10;
//一个模拟
struct node {
	int id;
	node(){};
	node(int _id) {
		id = _id;
	}
};

struct Node {
	int id,k;
	vector<node>v;
	bool operator < (const Node& a) const {
		return k < a.k;
	}
}day[N];

int n,m,ans[N],cnt[N];
bool cmp(node a,node b) {
	return cnt[a.id] < cnt[b.id];
}

int main() {
	int T;scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&n,&m);
		for(int i = 0;i <= n;i ++) cnt[i] = 0;
		for(int i = 0;i <= m;i ++) day[i].v.clear();
		int ma = (m + 1) / 2;
		int a;
		for(int i = 1;i <= m;i ++) {
			scanf("%d",&day[i].k);
			for(int j = 1;j <= day[i].k;j ++) {
				scanf("%d",&a);
				day[i].v.pb(node(a));
			}
			day[i].id = i;
		}
		sort(day + 1,day + 1 + m);//把k值小的放在前面
		int fg = 0;
		for(int i = 1;i <= m;i ++) {
			sort(day[i].v.begin(),day[i].v.end(),cmp);
			node cur = day[i].v[0];
			cnt[cur.id]++;
			if(cnt[cur.id] > ma) {
				fg = 1;
				break;
			}
			ans[day[i].id] = cur.id;
		}
		if(fg) {
			puts("NO");
		}
		else {
			puts("YES");
			for(int i = 1;i <= m;i ++) {
				printf(i == m?"%d\n":"%d ",ans[i]);
			}
		}
	}
	return 0;
}

D - Playlist

题意:
给定你一个歌曲播放序列,每个歌曲都有对应的一个标志 a i a_i ai,假如当前歌曲的 a i a_i ai和播放列表中上一首歌曲 a j a_j aj,二者 g c d ( a i , a j ) = = 1 gcd(a_i,a_j) == 1 gcd(ai,aj)==1,则从播放列表中删去这首歌曲,并从下一首歌曲重新开始计数。
思路:
模拟一个链表的操作即可,不断维护当前节点和和它的 n e x t next next指针,知道当前列表中已经没有连续的互质位置。

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 2e5 + 10;
int n,a[N],nex[N];
std::map<int,bool>vis;
int gcd(int a,int b) {
	return b == 0 ? a : gcd(b,a%b);
}
std::queue<pii>adjacent;//存储可以删除的歌曲序列
std::vector<int>ans;//存答案

int main() {
	int T;scanf("%d",&T);
	while(T--) {
		scanf("%d",&n);
		ans.clear();
		vis.clear();
		memset(nex,0,sizeof(nex));
		for(int i = 1;i <= n;i ++) {
			scanf("%d",&a[i]);
			i == n ? nex[i] = 1 : nex[i] = i + 1;
		}
		// for(int i = 1;i <= n;i ++) cout << i << ' ' << nex[i] << '\n';
		for(int i = 1;i <= n;i ++) {
			if(gcd(a[i],a[nex[i]]) == 1) {
				adjacent.push(MP(i,nex[i]));
			}
		}
		while(!adjacent.empty()) {
			pii p = adjacent.front();
			adjacent.pop();
			if(vis[p.first] || vis[p.second]) continue;
			ans.pb(p.second);
			nex[p.first] = nex[p.second];//注意链表的next指针维护操作
			vis[p.second] = 1;
			if(gcd(a[p.first],a[nex[p.second]]) == 1) {
				adjacent.push(MP(p.first,nex[p.second]));
			}
		}
		printf("%d",sz(ans));
		for(int i = 0;i < sz(ans);i ++) printf(" %d",ans[i]);
		puts("");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值