【Codeforces 1475】Codeforces Round #697 (Div. 3) | 全题解

比赛连接

emm,消极了,消极了。这场可以 a k ak ak的,看到 u n r unr unr不想打了,奇怪了,本身我也不加分的呀。

赛后 3 3 3分钟过 G G G 10 10 10分钟过 F F F,不该消极的。

不传播负能量了,开始题解了。

A.Odd Divisor

题目大意:

判断一个整数 n n n,是否具有为奇数的因子

题目思路:

水题了吧.

只需要判断是否是2的幂即可,不是2的幂必定有奇数因子呀。

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e6+700;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int main(){
    
    
	int T;scanf("%d",&T);
	while(T--){
    
    
		read(n);
		while(n!=1){
    
    
			if(n%2 == 0) n/=2;
			else break;
		}
		printf("%s\n",n==1?"NO":"YES");
	}
 	return 0;

}
/***
7
6 6 2 7 4 2 5
7
1 3 6
2 1 2 2
***/

B.New Year’s Number

题目大意:

判断一个整数 n n n,是否可以有若干个 2020 2020 2020和若干个 2021 2021 2021组成

题目思路:

x = n / 2020 x = n/2020 x=n/2020:

  • x = = 0 x == 0 x==0 : N O NO NO
  • n % 2020 < = x n\%2020 <= x n%2020<=x : Y E S YES YES

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e6+700;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
int main(){
    
    
	int T;scanf("%d",&T);
	while(T--){
    
    
		read(n);
		ll temp = n/2020;
		if(temp <= 0) printf("NO\n");
		else{
    
    
			if(n%2020 <= temp) printf("YES\n");
			else printf("NO\n");
		}
	}
 	return 0;

}
/***
7
6 6 2 7 4 2 5
7
1 3 6
2 1 2 2
***/

C.Ball in Berland

题目大意:

其实这题目,我没读完,猜的题意。

询问有多少对 ( a , b ) , ( c , d ) (a,b),(c,d) (a,b),(c,d)使得 a ! = c , b ! = d a != c,b != d a!=c,b!=d

题目思路:

显然的容斥原理:

假设 i i i可以与前面的 ( i − 1 ) (i-1) (i1)都组合,然后减去不符合要求的。

A A A集合代表男生在同一集合, B B B代表女生在同一集合,显然求: A ∪ B A∪B AB

m a p map map存一下,直接容斥原理就好了。

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e6+700;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
map<int,int>A,B;
map<pair<int,int>,int>C;
ll a[maxn],b[maxn];
int main(){
    
    
	int T;scanf("%d",&T);
	while(T--){
    
    
		ll att,bt;
		read(att);read(bt);read(n);
		A.clear();B.clear();C.clear();
		for(int i=1;i<=n;i++) read(a[i]);
		for(int i=1;i<=n;i++) read(b[i]);
		ll ans = 0;
		for(int i=1;i<=n;i++){
    
    	
			

			ans += (i-1)*1ll - (A[a[i]]+B[b[i]]-C[{
    
    a[i],b[i]}]);
			A[a[i]]++;B[b[i]]++;
			C[{
    
    a[i],b[i]}]++;
			//debug(ans);
		}
		dl(ans);
	}
 	return 0;

}
/***
7
6 6 2 7 4 2 5
7
1 3 6
2 1 2 2
***/

D. Cleaning the Phone

题目大意:

抽象:给出 N N N个物品,每个物品有一个质量和花费,求出在质量大于等于 m m m时的最小花费。

题目思路:

其实这个题卡了略久(这场的原因都在这了)

看错题意没有发现 b i b_i bi只有两种取值,因为只有两种取值,所以可以直接枚举最终状态,即:取第一种取值的 b i b_i bi在最终答案中可能有多少个,之后按照贪心去计算最小花费。尺取二分都可,这里采用的二分。

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e6+700;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
struct node{
    
    
	ll x,y;
	bool friend operator<(node a,node b){
    
    
		if(a.y == b.y) return a.x > b.x;
		return a.y < b.y;
	}
}q[maxn];
ll sum[maxn];
int main(){
    
    
	int T;scanf("%d",&T);
	while(T--){
    
    
		read(n);read(m);
		for(int i=1;i<=n;i++) read(q[i].x);
		for(int i=1;i<=n;i++) read(q[i].y);
		sort(q+1,q+1+n);
		int last = 0;
		for(int i=1;i<=n;i++){
    
    
			if(q[i].y == 1) last = i;
			sum[i] = sum[i-1] + q[i].x;
		}
		if(sum[n]<m){
    
    
			printf("-1\n");
			continue;
		}
		ll ans = INF;
		for(int i=0;i<=last;i++){
    
    
			int l = last,r = n;
			int tmp = -1;
			while(l<=r){
    
    
				int mid = (l+r)/2;
				if(sum[mid]-sum[last] + sum[i] >= m){
    
    
					r = mid-1;
					tmp = mid;
				}else l = mid+1;
			}
			if(tmp!=-1) ans = min(ans,i*1 + (tmp-last)*2ll);
		}
		printf("%lld\n",ans);
	}
 	return 0;

}
/***
7
6 6 2 7 4 2 5
7
1 3 6
2 1 2 2
***/

E. Advertising Agency

题目大意:

首先令 m x = mx = mx=数组的长度为k的最大子序列和。

询问有多少个长度为 k k k的子序列的和 = m x = mx =mx

题目思路:

这题估计挺多做法的

d p i j dp_{ij} dpij代表以第i个数字结尾,长度为j的子序列的最大和。
c i j c_{ij} cij代表以第i个数字结尾,长度为j的子序列的最大和的数量。

首先类比最短路计数的状态转移得到:

  • d p [ i ] [ j ] < d p [ k ] [ j − 1 ] + a [ i ] − > d p [ i ] [ j ] = d p [ k ] [ j − 1 ] + a [ i ] , c [ i ] [ j ] = c [ k ] [ j − 1 ] dp[i][j] < dp[k][j-1]+a[i] -> dp[i][j] = dp[k][j-1]+a[i],c[i][j] = c[k][j-1] dp[i][j]<dp[k][j1]+a[i]>dp[i][j]=dp[k][j1]+a[i],c[i][j]=c[k][j1]
  • d p [ i ] [ j ] = d p [ k ] [ j − 1 ] + a [ i ] − > c [ i ] [ j ] = c [ i ] [ j ] + c [ k ] [ j − 1 ] dp[i][j] = dp[k][j-1]+a[i] -> c[i][j] = c[i][j] + c[k][j-1] dp[i][j]=dp[k][j1]+a[i]>c[i][j]=c[i][j]+c[k][j1]
  • 1 ≤ k < i 1 \le k \lt i 1k<i

显然是个三维循环,但是与最大值有关系,所以用前缀最大值,和前缀最大值的数量优化掉一层 f o r for for即可

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e6+700;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
ll dp[1005][1005],c[1005][1005];
ll pre[1005],ct[1005];
ll a[maxn];
int main(){
    
    
	int T;scanf("%d",&T);
	while(T--){
    
    
		read(n);read(m);
		for(int i=1;i<=n;i++) read(a[i]);

		memset(ct,0,sizeof(ct));
		memset(pre,0,sizeof(pre));
		for(int i=0;i<=n;i++)
			for(int k=0;k<=m;k++)
				dp[i][k] = c[i][k] = 0;
		c[0][0] = 1;
		ct[0] = 1;
		for(int i=1;i<=n;i++){
    
    
			for(int j=1;j<=m;j++){
    
    
				if(dp[i][j]<pre[j-1]+a[i]){
    
    
					dp[i][j] = pre[j-1]+a[i];
					c[i][j] = ct[j-1];
				}else if(dp[i][j] == pre[j-1]+a[i]) c[i][j] = (c[i][j] + ct[j-1])%mod;
			}
			for(int j=0;j<=m;j++){
    
    
				if(pre[j]<dp[i][j]){
    
    
					ct[j] = c[i][j];
					pre[j] = dp[i][j];
				}else if(pre[j] == dp[i][j]) ct[j] = (ct[j] + c[i][j])%mod;
			}
		}
		ll ans = 0,mx = 0;
		for(int i=1;i<=n;i++) mx = max(mx,dp[i][m]);
		//debug(mx);
		for(int i=1;i<=n;i++) 
			if(mx == dp[i][m])
				ans = (ans + c[i][m])%mod; 
		dl(ans);
	}
 	return 0;

}
/***
7
6 6 2 7 4 2 5
7
1 3 6
2 1 2 2
***/

F. Unusual Matrix

题目大意:

给出两个 01 01 01矩阵, s s s t t t。每次可以将 s s s的一行进行异或,或者将 t t t的一行进行异或,询问是否可以通过一系列的操作使得 s s s变成 t t t

题目思路:

一个思维题。

可以考虑对 ( i , j ) (i,j) (i,j)操作的关联性,对 ( i , j ) (i,j) (i,j)操作就会改变 ( 1 , j ) (1,j) (1,j)或者 ( i , 1 ) (i,1) (i,1)的值,但是这两个还可以通过 ( 1 , 1 ) (1,1) (1,1)再改变回来。所以这四个就是一个关联组。当全一样或者全不一样的时候就不可以使得四个都满足。

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e6+700;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
char s[maxn];
int c[1005][1005];
int main(){
    
    
	int T;scanf("%d",&T);
	while(T--){
    
    
		read(n);
		for(int i=1;i<=n;i++){
    
    
			scanf("%s",s+1);
			for(int k=1;k<=n;k++) c[i][k] = s[k]-'0';
		}
		for(int i=1;i<=n;i++){
    
    
			scanf("%s",s+1);
			for(int k=1;k<=n;k++) c[i][k] ^= s[k]-'0';
		}
		int flag = 0;
		for(int i=2;i<=n;i++){
    
    
			for(int k=2;k<=n;k++){
    
    
				if(c[1][k]^c[i][1]^c[1][1]^c[i][k]) flag = 1; 
			}
		}
		printf("%s\n",flag?"NO":"YES");
	}
 	return 0;

}
/***
7
6 6 2 7 4 2 5
7
1 3 6
2 1 2 2
***/

G. Strange Beauty

题目大意:

定义一个数组是好的,当前仅当任意两个数 i , j i,j i,j都满足 a i ∣ a j a_i | a_j aiaj 或者 a j ∣ a i a_j | a_i ajai

问最少删除几个数使得数组变好。

题目思路:

考虑从小到大将数组排序(其实并不用,方便理解)

d p i dp_i dpi代表最大值是 a i a_i ai好的数组的最大容量是多少

那么很显然:

i f ( a k % a i = = 0 ) if(a_k\%a_i==0) if(ak%ai==0) d p [ i ] = d p [ k ] + a i dp[i] = dp[k] + a_i dp[i]=dp[k]+ai的数量

R e a s o n : Reason: Reason:最大值是 a k a_k ak a i a_i ai肯定也整除 a k a_k ak整除的数

所以只需要知道有哪些因子即可 —— 筛法筛一筛?

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e6+700;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
ll a[maxn];
ll vis[maxn];
ll c[maxn],w[maxn];
ll dp[maxn];
vector<int>v[maxn];
int main(){
    
    
	int T;scanf("%d",&T);
	while(T--){
    
    
		read(n);
		ll mx = 0;
		for(int i=1;i<=n;i++){
    
    
			read(a[i]);
			mx = max(mx,a[i]);
			vis[a[i]]++;
		}
		for(int i=1;i<=mx;i++){
    
    
			v[i].clear();
			dp[i] = 0;
		}
		ll ans = INF;
		for(int i=1;i<=mx;i++){
    
    
			for(int k=2*i;k<=mx;k+=i)  v[k].push_back(i);
		}
		sort(a+1,a+1+n);
		//for(int i=1;i<=n;i++) printf("%lld ",a[i]);
		for(int i=1;i<=n;i++){
    
    
			dp[a[i]] = vis[a[i]];
		
			for(int e:v[a[i]]) dp[a[i]] = max(dp[e]+vis[a[i]],dp[a[i]]);
			//debug(dp[a[i]]);
			int k = i;
			ans = min(ans,n-dp[a[i]]);
			while(a[k] == a[i] && k<=n) k++;
			i = k-1;

		}
		printf("%lld\n",ans);
		for(int i=1;i<=n;i++) vis[a[i]]--;
	}
 	return 0;

}
/***
7
6 6 2 7 4 2 5
7
1 3 6
2 1 2 2
***/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/113158367