昨天div3阿克了~

A题模拟看题意;

#include<iostream>
 
using namespace std;
 
const int N = 310;
int a[N];
 
int main(){
	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		for(int i = 1; i <= n; i++){
			cin >> a[i];
		}
		int l = 1,r = n;
		for(int i = 1; i <= n; i++){
			if(i != 1) cout << " ";
			if(i % 2){
				cout << a[l++];
			}else cout << a[r--];
		}
		cout << endl;
	}
	
	
	
	return 0;
}

B题的意思是去掉一部分使数组只剩2020
很明显要么就是2020 或者 2.。。。020 或者
20.。。20,202.。。。0,2020.。。

#include<iostream>

using namespace std;

const int N = 310;
int a[N];

int main(){
	int t;
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		string a;
		cin >> a;
		bool flag = false;
		int len = a.length();
		if(a[0] == '2' && a[1] == '0' && a[2] == '2' && a[3] == '0'){
			flag = true;
		}else if(a[0] == '2' && a[1] == '0' && a[2] == '2' && a[len - 1] == '0'){
			flag = true;
		}else if(a[0] == '2' && a[1] == '0' && a[len - 2] == '2' && a[len - 1] == '0'){
			flag = true;
		}else if(a[0] == '2' && a[len - 3] == '0' && a[len - 2] == '2' && a[len - 1] == '0'){
			flag = true;
		}else if(a[len - 4] == '2' && a[len - 3] == '0' && a[len - 2] == '2' && a[len - 1] == '0'){
			flag = true;
		}
		if(flag) cout << "YES" << endl;
		else cout << "NO" << endl; 
	}
	
	
	
	return 0;
}

C题思路 一定是位数越小的数越小 所以只要从9往1找就行了

#include<iostream>
#include<cstring> 
 
using namespace std;
 
int flag[15];
 
int main(){
	int t;
	cin >> t;
	while(t--){
		memset(flag,0,sizeof flag);
		int n;
		cin >> n;
		//123456789
		if(n > 45){
			cout << "-1" << endl;
			continue;
		}
		for(int i = 9; i >= 1; i--){
			if(n >= i){
				flag[i] = i;
				n -= i;	
			}
		}
		for(int j = 1; j <= 9; j++){
			if(flag[j]) cout << flag[j];
		}
		cout << endl;
	}
	
	
	
	
	return 0;
}

D 因为数组的总值为sum 所以可以将数组分别分为 sum /2 + sum / 2 或者
sum / 3 + sum / 3 + sum / 3 直到 n个sum / n相加
并且sum 要是 i的整数倍 这块 直接跑一个on循环然后
判断是否成立即可

#include<iostream>

using namespace std;

typedef long long ll;

const int N = 3010;
int n,m,t;
int a[N],b[N];
int res;

int main(){
	cin >> t;
	while(t--){
		int n;
		cin >> n;
		int sum = 0;
		for(int i = 1; i <= n; i++){
			cin >> a[i];
			sum += a[i];
		}
		for(int i = n; i >= 1; i--){
			if(sum % i != 0){
				continue;
			}
			ll h = sum / i;
			ll change = n - i,cnt = 0,flag = 0;
			for(int j = 1; j <= n; j++){
				if(a[j] > h){
					flag = 1;
					break;
				}
				if(a[j] == h && (cnt == 0 || cnt == h)){
					cnt = 0;
					continue;
				}
				if(cnt == h) cnt = 0;
				if(a[j] != h){
					if(cnt != 0) change--;
					cnt += a[j];
				}
				if(cnt > h || (a[j] == h && cnt < h && cnt != 0)){
					flag = 1;
					break;
				}
			}
			if(!flag && change == 0){
				cout << n - i << endl;
				break;
			}
		}
		

	}
	return 0;
}

E1
大意就是在数组中随机取3个数 如果 max(a[i],a[j],a[k] - min(a[i],a[j],a[k]) <= 2即算一种 求一共有几种
这一看就直接sort就完事了然后双指针从头往后找一共有多少数
比如 1 1 2 2就可以变成取 第一个位置 和 第三个位置的方案 和 取 第1个位置
和取第 4 个位置的方案 那就是 cal(1,1) + cal(2,1);很明显 这样的方案一个个取特别耗时间 我们不如搞个数组 前缀和 将 1 - n的都开出来 整体的复杂度就是 3on

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 2e5 + 10;

typedef long long ll;

ll b[N];
int a[N];
int main(){
	int t;
	cin >> t;
	for(int i = 1; i <= N - 1; i++){
		b[i] = b[i - 1] + i;
	} 
	while(t--){
		int n;
		cin >> n;
		for(int i = 1; i <= n; i++){
			cin >> a[i];
		}
		sort(a + 1,a + n + 1);
		int l = 1,r = 3;
		ll sum = 0;
		while(l <= n - 2){
			while(a[r] - a[l] <= 2 && r < n){
				r++;
			}
			if(a[r] - a[l] > 2) r--;
			sum += b[r - l - 1];
			l++;
		}
		cout << 1ll * sum << endl;
	}
	
	
	
	return 0;
}

E2 的话就是翻版了
将3个变为n个 <= 2 变为 <= m
那么思路是一样的就是sort + 双指针
但是发现我们的前缀和已经不能用了
但是方案数还是一样的 就是 cal(n - 2,n - 2) + cal(n - 1,n - 2) + … + cal(k,n - 2)这个时候可以看出一个组合数学的常规公式
cal(n,m) = cal(n - 1,m - 1) + cal(n - 1,m);
所以上面的式子就可以转化为一个等式cal(k + 1,n - 1);
但是这样还是会超时 因为题目的数据 n 是2e5;
所以我们要想个logn的计算方式或者o1的计算方式
根据题目我们可以看到 m 是不超过100的 所以采用离线算法的化就是
n * m = 2e7 < 1e8 所以是可以实现的
所以我们只要预处理一个数组即可

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long ll;

const int N = 2e5 + 10,mod = 1e9 + 7;
int c[N][110];
int b[N];
int a[N];

ll qmi(ll a,ll b){
	ll s = 1;
	while(b){
		if(b & 1){
			s = s * a % mod;
		}
		a = a * a % mod;
		b >>= 1;
	}
	return s;
}

void init(){
	c[0][0] = 1;
	c[1][0] = 1,c[1][1] = 1;
	for(int i = 2; i <= N - 1; i++){
		c[i][0] = 1;
		for(int j = 1; j <= min(i,100); j++){
			c[i][j] = (c[i - 1][j - 1] + c[i - 1][j]) % mod;
		}
	}
}

ll cal(int x,int y){
	return c[y][x];
}

int main(){
	int t;
	cin >> t;
	
	init();
	
	while(t--){
		int n,m,k;
		scanf("%d%d%d",&n,&m,&k);
		/*for(int i = 1; i <= N - 1; i++){
			b[i] = b[i - 1] + cal(m - 2,m + i - 3);
			cout << b[i] << " " << cal(m - 1,m + i - 2) << endl;
		}// b[i] = cal(m - 1,m + i - 2) - cal(m - 2,m - 1);	 */
		for(int i = 1; i <= n; i++){
			scanf("%d",&a[i]);
		}
		sort(a + 1,a + n + 1);
		int l = 1,r = m;
		ll sum = 0;
		while(l <= n - m + 1){
			while(a[r] - a[l] <= k && r < n){
				r++;
			}
			while(a[r] - a[l] > k) r--;
			//cout << r << " " << l << "Asd" << " " << a[r].x << " " << a[l].x << endl;
			if(r - l >= m - 1) sum = (sum + cal(m - 1 ,r - l)) % mod;
			l++;
		} 
		printf("%lld\n",sum);
	}
	
	
	
	return 0;
}

F题的大意就是 使给出的片段中 能和别的片段都有交集的最少删减别的片段的个数

由题目可想到 我如果找到了那个最优的片段 我就要判断 有多少个片段的最右端值使小于我这个最优片段的最左端值 有多少片段的最左端值 是大于我这个最优片段的最大值 由这个思路 我们可以想到 枚举 + 二分 我用两个数组记录分别记录 我需要枚举的数组 另一个找最小的最右端的i值 和 找最大的左端值

#include<iostream>
#include<algorithm>

using namespace std;

const int N = 2e5 + 10;

struct node{
	int x,y;
}a[N],b[N];

int n,m;

bool cmp(node a,node b){
	return a.x < b.x;
}

bool cmp1(node a,node b){
	return a.y < b.y;
}

int c[N],d[N]; 

int main(){
	int t;
	cin >> t;
	while(t--){
		cin >> n;
		for(int i = 1; i <= n; i++){
			cin >> a[i].x >> a[i].y;
			b[i].x = a[i].x,b[i].y = a[i].y;
		}
		
		int maxn = 0x3f3f3f3f;
		sort(a + 1,a + n + 1,cmp);
		for(int i = 1; i <= n; i++){
			int sum = 0;
			int l = 1,r = n;
			while(l < r){
				int mid = l + r + 1 >> 1;
				if(b[i].y < a[mid].x){ 
					r = mid - 1;
				}else l = mid;
			}
			if(a[r].x > b[i].y){
				sum += n - r + 1;
			}else sum += n - r;
			c[i] = sum;
		}
		sort(a + 1,a + n + 1,cmp1);
		for(int i = 1; i <= n; i++){ 
			int sum = 0;
			int l = 1,r = n;
			while(l < r){
				int mid = l + r + 1 >> 1;
				if(b[i].x > a[mid].y){
					l = mid;
				}else r = mid - 1;
			}
			if(a[l].y < b[i].x){
				sum += l;
			}else if(a[l].y == b[i].x){
				sum += l - 1;
			}
			d[i] = sum;
		}
		
		for(int i = 1; i <= n; i++){
			maxn = min(maxn,c[i] + d[i]);
		}
		
		cout << maxn << endl;
	}
	
	
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值