梦熊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;
}