D. Zigzags
题意:![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/3b2c4001bb00c4e6db45256241c59ed2.png)
思路:
- 把问题转化为map来看:找 ( a i , a j ) = ( a k , a l ) (a_i,a_j)=(a_k,a_l) (ai,aj)=(ak,al)的个数
- 数据小:双层循环:外层从后往前遍历 k k k,再从 k k k往前遍历 i i i
- 第二层循环过程中途径的都是 a j a_j aj,记录多少个 a j = a l a_j=a_l aj=al。
- 遇到 a i = a k a_i=a_k ai=ak时,贡献为遍历途中多少个 a j = a l a_j=a_l aj=al
代码:
#include<bits/stdc++.h>
using namespace std;
#define fore(i,x,y) for(int i=x;i<=y;++i)
const int N = 3004;
typedef long long ll;
int a[N],cnt[N];
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
fore(i,1,n) scanf("%d",&a[i]);
ll k,ans=0;
memset(cnt,0,sizeof(cnt));
for(int i=n;i;--i){
k=0;
for(int j=i-1;j;--j){
if(a[i]==a[j]) ans+=k;
k+=cnt[a[j]];
}
cnt[a[i]]++;
}
printf("%lld\n",ans);
}
}
E. Clear the Multiset
题意:
一个multiset,a[i]意味着有a[i]个i数字,两种操作,(1)选一个i减少任意个(2)一个区间减少一个。用最少操作清空multiset。
思路:
- 顺序随意,固考虑先操作2再操作1。
- 分治:对每个状态,比较纯操作2优还是操作1后转移到下一个状态优
- 每次操作1必然是选取区间最小值,全员减这个最小值(故此处可用rmq优化为O(n))
代码:
时间复杂度:O(n^2)
#include<bits/stdc++.h>
using namespace std;
#define fore(i,x,y) for(int i=(x);i<=(y);++i)
const int N = 5003;
typedef long long ll;
ll inf = 1e10;
int a[N];
int rmq(int l,int r){
ll m=inf;int x;
fore(i,l,r) if(a[i]<m) m=a[i],x=i;
return x;
}
ll solve(int l,int r,int h){
if(l>r) return 0;
int m=rmq(l,r);
return min((ll)r-l+1,solve(l,m-1,a[m])+solve(m+1,r,a[m])+a[m]-h);
}
int main(){
int n;
scanf("%d",&n);
fore(i,1,n) scanf("%d",&a[i]);
printf("%lld\n",solve(1,n,0));
}