2021杭电多校5 :3,6,7; 多校6:1 5

多校5:
1003. VC Is All You Need
题目:能否用一条直线把n个点分成两部分,每一边的颜色是相同的。
思路:如果稍微了解过机器学习应该就会了。想一下对于四个点
在这里插入图片描述

你不能用一条直线直接分开。但是,如果你把右下角的红点翻折上来,这样就是一个三维平面,你就可以分开。而我们考虑最坏的情况,每次翻折只能使两个点变成一个点。那么四个点翻一次,五个点翻两次…
于是答案就呼之欲出了。
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int T;
	cin >> T;
	while(T--)
	{
		long long n, k;
		cin >> n >> k;
		if(n-1 <= k){
			cout << "Yes\n";
		}else{
			cout << "No\n";
		}
	}
}
  1. cut tree
    相当于翻译代码…
    题目代码

观察一下这个代码, 模拟就好
代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define ctx cout << "xxxxxxx" << endl
const int N = 2e5 + 10;
int a[N], n;
ll tot = 0;
int build(int l, int r)
{
	tot++;
	if(r == l){
		return tot;
	}
	if(r == l+1){
		build(l, l);
		build(r,r);
	}
	else{
		
		int b = l + (r-l+1)/3 - 1;
		int c = (b + r)/2;
		build(l, b);
		build(1, c-b);
		build(1,r-c); 
	}
}



int main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		cin >> n;
		for(int i = 1; i <= n; i++) cin >> a[i];
		tot = 0;
		build(1, n);
		cout << tot << endl;
		
	}
}
  1. Banzhuan
    题目: [1,n]×[1,n]×[1,n]的三维平面内放砖块,求最大和最小,放砖块的花费是x*y2*z。要求三视图是 n * n的正方形。
    思路:本题这个花费是最初放的位置,而且是有重力的。那么最多就是在最顶层放,让它自由下落。最少就是在最底层先放,然后沿着两边放。
    举个例子,对于3 * 3, z = 1 的时候。
    1 4 9
    2 8 18
    3 12 27
    很容易想到使题目成立可以用对角线,然后 ‘/’ 比较小,但是观察8旁边的2,4,如果我们选了,三视图不会影响,反而会减少花费。
    本题最难的是除法取模,一步一模的操作。
    代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 1e9 + 7;


ll ksm(ll a, ll b) {
	ll ans = 1;
	ll base = a % mod;
	while (b) {
		if (b & 1) ans = (ans * base) % mod;
		base = (base * base) % mod;
		b >>= 1;
	}
	return ans;
}

int main() {
	int t;
	cin >> t;
	while (t--)
	{
		ll n;
		cin >> n;
		n %= mod;
		ll tm1 = ((n * (n + 1 % mod) % mod) * ((2 * n % mod + 1) % mod)) % mod * ksm(6, mod - 2) % mod;         //i^2
		ll tm2 = (n * (n + 1) % mod) * ksm(2, mod - 2) % mod;                     //i^3
		tm2 = ((tm2 * n % mod) * (n + 1) % mod) * ksm(2, mod - 2) % mod;          //i^3
		ll tm3 = ((n % mod) * (n + 1 % mod) % mod) * ksm(2, mod - 2) % mod;         //1->n
		ll tm4 = (((n - 1 + mod) % mod) * (n + 2 % mod) % mod) * ksm(2, mod - 2) % mod;     //2->n
		ll tm5 = tm1 * tm3 % mod;                           // z=1
		ll tm6 = (tm1-1+mod)%mod;    // 2^2->n^2
		ll MIN = (tm5 % mod + (tm6+tm4%mod)*tm4%mod) % mod;
		ll MAX = ((tm5 * n) % mod * n) % mod;
		cout << MIN << endl << MAX << endl;
	}
}

多校6:
1001 Yes, Prime Minister
题目:给一个x, 求一段连续的区间[l, r] 使 Σ i r _i^r iri 是一个质数,且要求区间长度最小。
思路:对于一个数n,他可能本本身是一个质数,n+n-1可能是,n+n+1可能是,n+n-2不是,n+n+2不是,…找规律发现,只有长度为1 or 2 时有可能。
因此,先质数塞找质数,然后一直往后找。
对于正数,先找前面一个和后面一个,然后找不到就用负数抵消,找后面一个的正数,后面找的只用找后面。
对于负数,找它对应的正数,然后往后找一个,找不到就往后一位,直到找到为止。
0是3,特殊判断。

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define _ 0
const int inf = 0x3f3f3f3f;
const int N = 2e7 + 10;
bool book[N];
vector<int> qq;

void init(){
	for(int i = 2; i <= N; i++)
	{
		if(!book[i])
		for(int j = 2; i*j <= N; j++)
		{
			book[i*j] = 1;
		}
		
	}
}

void solve(){
	ll x;
	cin >> x;
	ll ans = 0;
	if(x == 0){
		cout << 3 << endl;
		return ;
	}
	if(x == 1){
		cout << 2 << endl;
		return;
	}	
	if (x > 0 && !book[x]) {
		cout << 1 << endl;
		return ;
	}
	if(x > 0){
		if(!book[x+x-1] || !book[x+x+1]){
			cout << 2 << endl;
			return;
		}
		ans = 2*x+2;
		for(int i = x+1; i <= N; i++){
			if(!book[i]){
				cout << ans << endl;
				return;
			}
			if(!book[2*i+1]){
				cout << ans + 1 << endl;
				return;
			}
			ans+=2;
		}
	}else{
		ans = abs(x*2) + 2;
		x = -x+1;
		if(!book[x]){
			cout << ans << endl;
			return ;
		}
		if(!book[2*x+1]){
			cout << ans+1 << endl;
			return;
		}
		ans += 2;
		for(int i = x+1; i <= N; i++){
			if(!book[i]){
				cout << ans << endl;
				return;
			}
			if(!book[i+i+1]){
				cout << ans+1 << endl;
				return;
			}
			ans += 2;
		}	
	}
}

int main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	init();
	int t;
	cin >> t;
	while(t--)
	{
	    solve();	
	}
	return ~~(0^_^0);
}
  1. Median
    题目:把[1,n]分成m个部分,使得中位数是b[i], 保证每个数不重复。能否?
    思路:把每一段都算出来,得到他们的个数,前面有多少个中位数。然后
    官方题解:

•如果长度最大的段的数字个数不大于其它段的数字个数之和,那么最终要么全部消掉,要么剩下一个,且剩下的这个数可以在任何一段内。如果会剩下,不妨将最后一段的数字剩下一个,此时再把最后一段的数字放到中位数最小的集合中即可满足题意,所以答案为 YES。
• 如果长度最大的段的数字个数大于其它段的数字个数之和,那么最终剩下的所有数字都在最大的这段内。设中位数小于这一段的最小值的集合的个数为 x,容易发现当且仅当 x 不小于这一段剩下的数字个数时有解。

第一个点原因是由于每一段都可以互相抵消,那么每一次都是抵消偶数个,那么要么剩下0个,要么是1个。
第二个点就是把其余的全部抵消后,还剩下的就是看有多少给中位数在前面。
我一开始没看懂的时候看的这里
代码:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define ctx cout << "xxxxxxx" << endl
#define int long long

const int N = 1e5 + 10;
int b[N];
bool book[N];

struct vv{
	int c1, c2;
};
bool cmp(vv d, vv j){
	return d.c1 < j.c1;
}

signed main(){
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int t;
	cin >> t;
	while(t--){
		int n, m;
		cin >> n >> m;
		memset(book, 0, sizeof(book));
		for(int i = 1; i <= m; i++){
			cin >> b[i];
			book[b[i]] = 1;
		}
		book[n+1] = 1;
		vector<vv> cot;
		int sum = 0, sum1 = 0;
		for(int i = 1; i <= n+1; i++){
			if(book[i]){
				if(sum) cot.push_back({sum, sum1});
				sum = 0;
				sum1++;
			}else{
				sum++;
			}
			
		}
		sort(cot.begin(), cot.end(),cmp);
		if(cot.size() == 0){
			cout << "YES\n";
			continue;
		}
		sum = 0;
		for(int i = 0; i < cot.size()-1; i++){	
			sum += cot[i].c1;
		}
		vv MX = cot.back();
		if(MX.c1 <= sum || (MX.c1 > sum && MX.c1 - sum <= MX.c2)){
			cout << "YES\n";
		}else{
			cout << "NO\n";
		}		
	}	
}

好好学习😶😶😶(居然可以发表情)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值