Codeforces Round #760 (Div. 3)


Codeforces Round #760 (Div. 3)

比赛的时候做了 $\mathrm{A,B,C,D,G}$.     

A. Polycarp and Sums of Subsequences

标签:模拟  

仔细观察发现 $\mathrm{b[1], b[2]}$ 恰好对应 $\mathrm{a[1], a[2]}$, 然后 $\mathrm{a[3]}$ 就是第 3 项或第 4 项.  

由于问题保证有解,所以只需判断一下是否是第三项即可.   

#include  
#define ll long long
#define pb push_back  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int a[10], b[10]; 
vectorg; 
int check(int x, int y, int z) {
	g.clear();  
	g.pb(x); 
	g.pb(y); 
	g.pb(z); 
	g.pb(x + y); 
	g.pb(x + z); 
	g.pb(y + z); 
	g.pb(x + y + z); 
	sort(g.begin(), g.end()); 
	for(int i = 1; i <= 7; ++ i) {
		if(a[i] != g[i - 1]) return 0; 
	}
	return 1;  
}
void solve() {
	int n = 7; 
	for(int i = 1; i <= n ; ++ i) {
		scanf("%d", &a[i]); 
	}
	//b[1] = a[1], b[2] = a[2];  
	if(check(a[1], a[2], a[3])) {
		printf("%d %d %d\n", a[1], a[2], a[3]); 
	}
	else {
		printf("%d %d %d\n", a[1], a[2], a[4]); 
	}

}
int main() {
	// setIO("input"); 
	int T; 
	scanf("%d", &T); 
	while(T-- ) solve(); 
	return 0; 
}

B. Missing Bigram

标签:模拟  

如果可以直接输出的话就在末尾随便加一个字符.  

否则可以在不合法的位置选择输出两个字符,其余位置输出一个即可. 

#include  
#define ll long long 
#define N  2009 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
char str[N][2]; 
void solve() {
	int n ; 
	scanf("%d", &n); 
	for(int i = 1; i <= n - 2; ++ i) {
		scanf("%s", str[i]); 
	}
	printf("%c%c", str[1][0], str[1][1]); 
	int flag = 0; 
	for(int i = 2; i <= n - 2; ++ i) {
		if(str[i - 1][1] != str[i][0]) {
			flag = 1; 
			printf("%c%c", str[i][0], str[i][1]); 
		}
		else {
			printf("%c", str[i][1]); 
		}
	}
	if(!flag) printf("%c", 'a');  
	printf("\n"); 
}
int main() {
	// setIO("input");
	int T; 
	scanf("%d", &T); 
	while(T -- ) solve();  
	return 0;
}

C. Paint the Array

标签:$\mathrm{gcd}$ 相关.  

可以枚举是奇数下标还是偶数下标可以被钦定的 $\mathrm{d}$ 整除.  

那么显然这个 $\mathrm{d}$ 必须是所有数字的 $\mathrm{gcd}$.   

然后显然对于不能被 $\mathrm{d}$ 整除的位置条件应该苛刻,所以直接取 $\mathrm{d}$ 作为答案即可. 

#include 
#define N  104
#define ll long long  
#define pb push_back 
#define setIO(s) freopen(s".in","r",stdin)  
using namespace std;
ll a[N]; 
int n ;
vectorg[2];
ll gcd(ll x, ll y) {
	return y ? gcd(y, x % y ) : x;  
}   
ll lcm(ll x, ll y) {
	return x / gcd(x, y) * y;   
}
ll sol(int o) {
	if(!g[o].size()) return 0;   
	ll gc = g[o][0];  
	for(int i = 0 ; i < g[o].size() ; ++ i) {
		gc = gcd(gc, g[o][i]);
	}  
	for(int i = 0; i < g[o ^ 1].size() ; ++ i) {
		if(g[o ^ 1][i] % gc == 0) return 0; 
	}
	return gc;  
}
void solve() {
	scanf("%d", &n); 
	g[0].clear(); 
	g[1].clear(); 
	for(int i = 1; i <= n ; ++ i) {
		scanf("%lld", &a[i]);
		g[i % 2].pb(a[i]); 
	}
	// d comes from g[0]  
	ll p = max(sol(0), sol(1));
	printf("%lld\n", p);   
}
int main() {
	//setIO("input");
	int T; 
	scanf("%d", &T); 
	while(T -- ) solve(); 
	return 0; 
}

  

D.  Array and Operations

标签:贪心,众数

贪心选择将最大的 $\mathrm{2K}$ 个数字操作掉.  

那么操作这些数字的时候贡献要么是 $\mathrm{0}$ 要么是 $1$.  

只需把众数的个数拿出来,然后讨论一下是否会出现 $1$ 的情况即可. 

#include 
#define N  1004 
#define setIO(s) freopen(s".in","r",stdin)  
using namespace std; 
int n , a[N], bu[200009], K; 
bool cmp(int i, int j) { return i > j; }
void solve() {
	scanf("%d%d", &n, &K);   
	for(int i = 1; i <= n ;++ i) {
		scanf("%d", &a[i]); 
		//bu[a[i]] ++ ;  
	}  
	sort(a + 1, a + 1 + n, cmp); 
	for(int i = 1; i <= 2 * K ; ++ i) {
		bu[a[i]] ++ ; 
	}
	int sum = 0; 
	for(int i = 2 * K + 1; i <= n ; ++ i) sum += a[i]; 
	int mx = 0; 
	for(int i = 1; i <= 2 * K ; ++ i) mx = max(mx, bu[a[i]]); 
	if(mx > K) {
		int c1 = mx, c2 = 2 * K - mx;   
		sum += (c1 - c2) / 2;    
	} 
	for(int i = 1; i <= n ; ++ i) bu[a[i]] = 0; 
	printf("%d\n", sum); 
}
int main() {
	// setIO("input"); 
	int T; 
	scanf("%d", &T); 
	while(T--) solve(); 
	return 0; 
}

E. Singers' Tour 

标签:模拟,性质分析 

显然可以直接确定 $\mathrm{a[i]}$ 之和.  

然后可以考虑相邻的 $\mathrm{b[i]}$ 之间的不同,发现这个不同是 $\mathrm{\sum a + n \times a[i]}$.  

然后就能将 $\mathrm{a[i]}$ 解出来了,答案其实是唯一的. 

#include  
#define N  100009 
#define ll long long 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int n; 
ll b[N], a[N]; 
void solve() {
	scanf("%d", &n); 
	ll sum = 0; 
	for(int i = 1; i <= n ; ++ i) {
		scanf("%lld", &b[i]); 
		sum += b[i]; 
	}
	ll tot = 1ll * (n + 1) * n / 2; 
	if(sum % tot) {
		printf("NO\n"); 
		return ; 
	}
	// 
	// b[i] = b[i - 1] + sum(a[i]) - (n - 1)  * a[i];      
	ll pa = sum / tot;   
	// printf("%lld\n", pa); 
	for(int i = 1; i <= n ; ++ i) {
		int prev = (i - 2 + n) % n + 1;    
		ll det = (b[prev] - b[i] + pa);    
		// printf("%lld %lld %lld %lld\n",b[prev], b[i], det, pa);   
		if(det <= 0) {
			printf("NO\n"); 
			return ; 
		}
		if(det % n) {
			printf("NO\n"); 
			return ; 
		}
 
		a[i] = det / n; 
	}
	printf("YES\n"); 
	for(int i = 1; i <= n; ++ i) {
		printf("%lld ", a[i]); 
	}
	printf("\n"); 
	// exit(0); 
}
int main() {
	// setIO("input"); 
	int T; 
	scanf("%d", &T); 
	while(T -- ) solve(); 
	return 0; 
}

F. Reverse

标签:二进制,模拟 

不难发现加 0 的操作就是将二进制序列翻转,然后 + 1 的操作是 + 1 后翻转.  

由于每个数字最多会有 2 个分叉,所以直接暴力搜索用 $\mathrm{map}$ 记录一下即可. 

#include  
#define ll long long 
#define pb push_back 
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
int bu[103];      
mapvs;     
ll bin[103], X, Y;    
void init() {
	for(int i = 0; i < 64 ; ++ i) bin[i] = 1ll << i; 
}
ll rev(ll x) {
	int le = 0; 
	while(x) {
		bu[++ le] = x & 1;
		x >>= 1; 
	}
	ll tp = 0; 
	for(int i = 1; i <= le; ++ i) {
		tp += 1ll * bu[i] * bin[le - i];   
	}
	// printf("%lld qaq\n", tp); 
	// exit(0); 
	return tp;   
}
int get_len(ll x) {
	int le = 0; 
	while(x) {
		++ le;
		x >>= 1; 
	}
	return le;  
}

void dfs(ll x) {    
	// printf("%lld\n", x); 
	vs[x] = 1;  
	if(x == Y) {
		printf("YES\n"); 
		exit(0); 
	}
	ll tmp = rev(x);     
	ll t1 = rev(x * 2 + 1);  
	// printf("%lld %lld\n", tmp, t1);
	// printf("%d %d\n", get_len(t1), get_len(tmp));  
	if(!vs[t1] && get_len(t1) <= get_len(Y)) {
		dfs(t1);    
		// +1 后翻转.            
	}    
	if(!vs[tmp] && get_len(tmp) <= get_len(Y)) {
		dfs(tmp);  
	}
}
int main() {
	// setIO("input"); 
	init();    
	scanf("%lld%lld", &X, &Y);
	dfs(X);  
	printf("NO\n"); 
	return 0; 
}

G. Trader Problem

标签:并查集   

可以把所有数字放到一起排序,那么如果一个数字可以达到第一个比他大的数字就连边.   

然后数字序列就构成了若干个连通块,每一个连通块的贡献就是前 $\mathrm{num[i]}$ 大的数字和.  

这里 $\mathrm{num[i]}$ 代表这个连通块中包含初始数字的个数.   

这个模型可以将询问离线从小到大排序,然后挨个合并并查集即可. 

#include  
#define N  400009 
#define ll long long
#define pb push_back  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;
int n, m, Q;  
struct Query  {
	int K, id;  
	Query(int K = 0, int id = 0):K(K), id(id) {}
}q[N]; 
bool cq(Query i, Query j) {
	return i.K < j.K; 
}
int num[N]; 
ll ans[N], sum[N], fin[N];  
struct Node {
	int x, id; 
	Node(int x = 0, int id = 0):x(x),id(id){}  
}A[N]; 
bool cmp(Node i, Node j) {
	return i.x < j.x; 
}     
struct DET {
	int pos, det;  
	DET(int pos = 0, int det = 0):pos(pos), det(det){}  
}arr[N];   
int fa[N]; 
int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]); 
}
bool DE(DET i, DET j)  { return i.det < j.det;   }   
ll ou[N]; 
int main() {
	// setIO("input"); 
	scanf("%d%d%d", &n, &m, &Q); 
	for(int i = 1; i <= n ; ++ i) {
		scanf("%d", &A[i].x); 
		A[i].id = 1; 
	}
	for(int i = 1; i <= m ; ++ i) {
		scanf("%d", &A[i + n].x); 
		A[i + n].id = 0; 
	}  
	int tot = n + m; 
	ll ans = 0; 
	sort(A + 1, A + 1 + tot, cmp); 
	for(int i = 1; i <= tot; ++ i) {
		sum[i] = sum[i - 1] + A[i].x;  
		if(A[i].id) ans += A[i].x; 
	} 
	// printf("%lld\n", ans); 
	for(int i = 1; i <= tot; ++ i) {
		fa[i] = i;  
		if(A[i].id == 1) num[i] = 1, fin[i] = A[i].x;   
	}
	for(int i = 1; i < tot; ++ i) {
		int de = A[i + 1].x - A[i].x;                 
		arr[i] = DET(i, de);    
	}
	sort(arr + 1, arr + tot, DE);   
	for(int i = 1; i <= Q; ++ i) {
		int kth; 
		scanf("%d", &kth); 
		q[i] = Query(kth, i); 
	}
	sort(q + 1, q + 1 + Q, cq); 
	for(int i = 1, j = 1; i <= Q; ++ i) {
		for(; j <= (tot - 1) && arr[j].det <= q[i].K; ++ j) {
			int p = arr[j].pos;     
			int ori = sum[p];  
			fa[p] = p + 1;  
			int now = find(fa[p]);  
			num[now] += num[p];  
			ans -= fin[p]; 
			ans -= fin[now]; 
			fin[now] = sum[now] - sum[now - num[now]];  
			ans += fin[now];    
		}
		ou[q[i].id] = ans; 
	}
	for(int i = 1; i <= Q; ++ i) {
		printf("%lld\n", ou[i]); 
	}
	return 0; 
}

相关