THIRD PROGRAMMING CONTEST 2023 ALGO(AtCoder Beginner Contest 318)
A - Full Moon
思路:模拟
直接模拟即可,找到以m开始每一次可以调p的距离终点为n的次数
c++
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m,q;cin>>n>>m>>q;
int res=1;
while(n>m){
m+=q;
res++;
}
if(n<m)res--;
cout<<res;
}
B - Overlapping sheets
思路:暴力
由于矩阵不是很大,之间标记每一组能覆盖的点即可
c++
#include<bits/stdc++.h>
using namespace std;
int a[110][110];
int main(){
int n;
int res=0;
cin>>n;
while(n--){
int x,y,x1,y1;
cin>>x>>y>>x1>>y1;
for(int i=x;i<=y-1;i++){
for(int j=x1;j<=y1-1;j++)a[i][j]++;
}
}
for(int i=0;i<=100;i++){
for(int j=0;j<=100;j++)if(a[i][j]>0)res++;
}
cout<<res;
}
C - Blue Spring
思路:贪心+排序
我们先排个序,然后计算d天花费和特价票的价格的大小,如果特价更优惠就跟新需要花费的钱
c++
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e6+7;
int a[N],s[N];
signed main(){
int n,d,p;
cin>>n>>d>>p;
int sum=0;
for(int i=1;i<=n;i++){
cin>>a[i];
sum+=a[i];
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
s[i]=s[i-1]+a[i];
}
int id=n;
while(id){
if(id-d<0)d=id;
int m=s[id]-s[id-d];
//cout<<m<<endl;
if(m>p){
sum-=(m-p);
id=id-d;
}else break;
}
// cout<<id<<endl;
cout<<sum;
}
D - General Weighted Max Matching
思路:dfs
一眼看过去这是一般图的最大权独立集,根本没啥多项式做法。
所以就直接爆搜的就好了,也就是对于每一个点找它匹配的点,需要注意的是可以有点不匹配边。
这样的复杂度就是 O(N!!)O(N!!) 显然可以过。
c++
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 20;
int n,match[N],d[N][N],ans,sum;
void dfs(int now){
if(now == n + 1){
ans = max(ans,sum);
return;
}
if(match[now]){
dfs(now+1);
return;
}
for(int i=now+1; i<=n; i++){
if(match[i]) continue;
match[now] = i,match[i] = now;
sum += d[now][i];
dfs(now+1);
match[now] = match[i] = 0;
sum -= d[now][i];
}
dfs(now+1);
}
signed main(){
scanf("%lld",&n);
for(int i=1; i<=n; i++){
for(int j=i+1; j<=n; j++){
scanf("%lld",&d[i][j]);
}
}
dfs(1);
printf("%lld\n",ans);
return 0;
}
E - Sandwiches
思路:前后缀数组
由于数有105,我们只能枚举其中一个。要么枚举 i要么枚举 j。分别考虑后发现枚举 j简单一点。
如果枚举下标i会发现比较难计算,对于当前的 ai,那么对于之后的每个 ak都要考虑它们之间的其他数的个数,感觉复杂度会比较大。
考虑枚举下标j,剩下的就是考虑 j左边和 j右边的相同数。这个j对答案的贡献就是 ∑x≠ajlx×rx,其中 lx表示 j左边 x(是值,不是下标)的个数, rx就是右边的 x的个数。
考虑当 j移动时,只有 aj和 aj+1这两个数的个数发生变化。因此我们事先维护 ∑的值,∑−laj×raj就是此时的 j对答案的贡献。转移时通过加减那两个数的贡献,就得到 j移动到下一个数时的 ∑的值。然后累计就是答案了
c++
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;cin>>n;
vector<int>a(n+10,0);
vector<int>l(n+10,0),r(n+10,0);
for(int i=0;i<n;i++){
int x;
cin>>x;
a[i]=x;
r[a[i]]++;
}
int ans=0;
int res=0;
for(int i=0;i<n;i++){
res-=1ll*(l[a[i]]*r[a[i]]);
ans+=res;
r[a[i]]--;
l[a[i]]++;
res+=1ll*(l[a[i]]*r[a[i]]);
}
cout<<ans;
}