梦熊2024--四月份--基础算法组

A


这个题是一个暴力
判断是否全在对角线上或下,两次二重循环即可,如果是,直接乘起来。

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

const int mo = 1e9+7;

int n;
int a[805][805];

bool x(){
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j < i;++ j){
			if(a[i][j] != 0) return false;
		}
	return true;
}

bool s(){
	for(int i = 1;i <= n;++ i)
		for(int j = i+1;j <= n;++ j){
			if(a[i][j] != 0) return false;
		}
	return true;
}

signed main(){
	
	cin >> n;
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j <= n;++ j)
			cin >> a[i][j];
	
	int ans = 1;
	if(x()||s()){
		for(int i = 1;i <= n;++ i){
			ans *= a[i][i];
			ans %= mo;
		}
		cout << ans;
	}
	else cout << "Arknights!";
	
	return 0;
	
}

B


这个题和\(ABC347\)\(c\)很像。
很显然的一个性质,如果区间长度\(\geq T\),一定可以消灭。
不管是在哪个位置,映射到\(1\)~\(T\)(这时只剩长度\(\leq T\)的了)。
判断那个位置能消耗的生命值最小,即可。

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n,t,sum,ans;
int l[100005],r[100005],v[100005];
int cf[200005];
int cn;

signed main(){
	
	cin >> n >> t;
	for(int i = 1;i <= n;++ i){
		cin >> l[i] >> r[i] >> v[i];
		sum += v[i];
		if(r[i]-l[i]+1 >= t){
			cn += v[i];
			continue;
		} 
		int y = l[i];
		l[i] %= t;
		if(l[i] == 0) l[i] = t;
		r[i] -= (y-l[i]);
		r[i] = min(r[i],2*t);
		cf[l[i]] += v[i];
		cf[r[i]+1] -= v[i];
	}
	
	for(int i = 1;i <= 2*t;++ i)
		cf[i] += cf[i-1];
	
	for(int i = 1;i <= t;++ i)
		ans = max(ans,cf[i]+cf[i+t]);
	
	ans += cn;
	ans = sum-ans;
	
	cout << ans;
	
	return 0;
	
}

C


这个题很有意思。
他虽然说是区间长度大于等于\(k\),但其实最优区间长度一定可以等于\(k\)
于是只需要用单调队列求最大最小值即可。
关于为什么最优区间长度一定可以等于\(k\)
设已经等于\(k\)了,考虑向右增大区间。
如果让最大值更大了,肯定更好,但是如果让最小值变小了,不好。
考虑如果让最大值更大了,我们可以把左边也增大,最小值可能还会变小,很好。
所以最优区间长度一定可以等于\(k\)

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n,k;
int a[100005];

int xq[100005];
int nq[100005];
int hx = 1,hn = 1,tx,tn;
int ans = -1e18;

void pux(int x){
	while(a[xq[tx]] > a[x]&&hx <= tx) tx--;
	xq[++tx] = x;
}

void pun(int x){
	while(a[nq[tn]] < a[x]&&hn <= tn) tn--;
	nq[++tn] = x;
}

signed main(){
	
	cin >> n >> k;
	for(int i = 1;i <= n;++ i)
		cin >> a[i];
	
	for(int i = 1;i < k;++ i)
		pux(i),pun(i);
	
	for(int i = k;i <= n;++ i){
		if(xq[hx] <= i-k) hx++;
		if(nq[hn] <= i-k) hn++;
		pux(i),pun(i);
		ans = max(ans,a[xq[hx]]+a[nq[hn]]);
	}
	
	cout << ans;
	
	return 0;
	
}

D


这个题是二分,考虑二分最大的费用,那么每一个数到这个价值都是一个一定大小的区间,只要看看所有的区间够不够所有区间即可。
\(check\)函数是\(O(n)\)的。
最后算答案是可以看出,多出的区间一定是多算了最大费用,减去即可。

点击查看代码
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n,L;
int v[100005];

int check(int x){
	int sum = 0;
	for(int i = 1;i <= n;++ i){
		int d = x/v[i];
		sum += d;
	}
	return sum;
}

signed main(){
	
	cin >> n >> L;
	for(int i = 1;i <= n;++ i)
		cin >> v[i];
	
	sort(v+1,v+1+n);
	
	int l = 0ll,r = 1e18,md;
	while(l < r){
		md = (l+r)/2;
		if(check(md) >= L) r = md;
		else l = md+1;
	} 
	
	int sum = 0;
	for(int i = 1;i <= n;++ i){
		int d = r/v[i];
		sum += v[i]*d*(d+1)/2;
	}
	int q = check(r);
	int e = q-L;
	sum -= e*r;
	cout << sum;
	
	return 0;
	
}
posted @ 2024-04-09 21:39  校牌杀手  阅读(72)  评论(0编辑  收藏  举报