ABC393

赛时通过:A,B,C

赛后通过:D,E,F

D

做法很多样化,我的想法就是取所有 1 的位置的中位数然后把它们移到那个地方周围,具体见代码。你说的对,这题非常简单,但是我忘记用缺省源了导致忘开 LL,赛后 eps s 通过。

实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;

const int N=5e5+5;
int n;
int tot,a[N];
string s;

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>s,s='#'+s;
	for(int i=1;i<=n;i++)
		if(s[i]=='1')
			a[++tot]=i;
	int k=(tot&1?(tot+1)/2:tot/2),ans=0;
	int last=a[k]-1;
	for(int i=k-1;i>=1;i--,last--)
		ans+=last-a[i];
	last=a[k]+1;
	for(int i=k+1;i<=tot;i++,last++)
		ans+=a[i]-last;
	cout<<ans<<'\n';
	return 0;
}

总结:开 LL

E

令答案为 \(x\),我们考虑满足什么条件的 \(x\) 可以成为答案:

  • \(x \mid A_i\)

  • \(A\) 里边有恰好 \(K\) 个数被 \(x\) 整除。

  • 最大。

观察到 \(A_i \le 10^6\),这提示我们可以枚举答案再去检验它。

第一个比较简单,直接枚举 \(x\) 倍数即可。

第二个的话,我可以预处理出每个数在 \(A\) 中出现的次数,然后对于每一个 \(x\) 的倍数累加这个次数即可统计出 \(A\) 中有多少个数可以被 \(x\) 整除。

第三个直接取 \(\max\) 就可以了。

然后我们注意到这个时间复杂度实际上是调和级数的,而非平方级别,因此可以承受。

实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;

const int N=2e6+5;
int n,k,a[N];
int m=-1e9,cnt[N],mcnt[N],ans[N];

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
		cin>>a[i],m=max(m,a[i]),cnt[a[i]]++;
	for(int i=1;i<=m;i++)
		for(int j=i;j<=m;j+=i)
			mcnt[i]+=cnt[j];
	for(int i=1;i<=m;i++)
		for(int j=i;j<=m;j+=i)
			if(mcnt[i]>=k)
				ans[j]=max(ans[j],i);
	for(int i=1;i<=n;i++)
		cout<<ans[a[i]]<<'\n';
	return 0;
}

总结:刻画答案法。

F

一眼 dp。

多组询问,考虑将询问离线,挂在 \(r\) 上,这样就可以一边 dp 一边回答询问了。

因为题目要求 LIS 中每个数都最多是 \(X_i\),这等价于最末尾的数 \(\le X_i\),于是定义 \(dp_i\) 表示长度为 \(i\) 的 LIS 末尾最小是多少。

转移:每次在 \(dp\) 中找第一个 \(\ge a_i\) 的数,然后用 \(a_i\) 替代它。

初始:均为 \(\infty\)

具体细节见代码。

实现
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define int long long
using namespace std;

const int N=2e5+5;
int n,q,a[N];
struct QUERY{
	int id,x;
};
vector<QUERY> qs[N];
int ans[N],dp[N]; 

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>n>>q;
	for(int i=1;i<=n;i++)
		cin>>a[i],dp[i]=1e10;
	for(int i=1;i<=q;i++){
		int r,x;
		cin>>r>>x;
		qs[r].push_back({i,x});
	}
	for(int i=1;i<=n;i++){
		int p=lower_bound(dp+1,dp+n+1,a[i])-dp;
		dp[p]=a[i];
		for(auto [id,x]:qs[i])
			ans[id]=upper_bound(dp+1,dp+n+1,x)-dp-1;
	}
	for(int i=1;i<=q;i++)
		cout<<ans[i]<<'\n';
	return 0;
}

总结:询问离线思想、dp 按位考虑思想

G

待补。

posted @ 2025-02-27 21:55  _KidA  阅读(16)  评论(0)    收藏  举报