A层邀请赛5

A层邀请赛5

A 赤

我不会wqs二分,但是这个题他是wqs二分套wqs二分。。。。

首先不难搞到一个n3DP

定义f[i][j][k]表示前i只猫,用了j个第一种零食,k个第二种零食的捕获的猫的期望,转移考虑当前猫用哪些零食

如何优化这个dp

我们想能不能砍掉一维,i显然砍不掉,j,k形式相同

我们尝试砍掉k

砍掉之后,直接dp显然会超出限制,用什么方法能够让选择更多第二种零食不是越多越优秀呢?

可以发现,如果每选一个b都给期望减去一个值,那么选第二种零食就不是越多越好

这令我们想到tree那个题,那么这个题是否可以wqs二分?

以横轴为选择第二种零食的数量,纵轴为期望,由于我们每次选取最优策略,所以斜率单调不增,这是一个上凸包!可以wqs二分

二分dtbdp时每选择一个第二种零食就减去一个dtb,同步处理使用第二种零食的数量,最后撤掉dtb的贡献,根据数量调整二分区间,(其实是改变斜率,不停的切凸包)

于是我们可以砍掉一维k,复杂度变成n2logn但是还是过不了

继续优化,我们上面提到j,k形式相同,那么k能砍掉,j为什么不能?

砍掉j以后,以同样的方式处理,每一次dta的二分都重新二分dtb

这样我们就有了wqs二分套wqs二分的nlog2n的优秀做法

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100003;
int n, a, b;
double pa[maxn], pb[maxn], pab[maxn];
double f[100005], ca[100005], cb[100005];
typedef pair<int, int> pii;
pii solve(double mid, double mid2){
	for(int i = 1; i <= n; ++i){
		f[i] = f[i - 1];
		ca[i] = ca[i - 1];
		cb[i] = cb[i - 1];
		if(f[i] < f[i - 1] + pa[i] - mid){
			f[i] = f[i - 1] + pa[i] - mid;
			ca[i] = ca[i - 1] + 1;
			cb[i] = cb[i - 1];
		}
		if(f[i] < f[i - 1] + pb[i] - mid2){
			f[i] = f[i - 1] + pb[i] - mid2;
			ca[i] = ca[i - 1];
			cb[i] = cb[i - 1] + 1;
		}
		if(f[i] < f[i - 1] + pab[i] - mid - mid2){
			f[i] = f[i - 1] + pab[i] - mid - mid2;
			ca[i] = ca[i - 1] + 1;
			cb[i] = cb[i - 1] + 1;
		}
	}
	return pii(ca[n],cb[n]);
}
int main(){
	while(~scanf("%d%d%d",&n, &a, &b)){
		for(int i = 1; i <= n; ++i)scanf("%lf",&pa[i]);
		for(int i = 1; i <= n; ++i)scanf("%lf",&pb[i]);
		for(int i = 1; i <= n; ++i)pab[i] = pa[i] + pb[i] - pa[i] * pb[i];
		double l = 0, r = 1, mid, ll = 0, rr = 1, midd;
		for(int i = 1; i <= 50; ++i){
			mid = (l + r) / 2;
			ll = 0, rr = 1;	
			for(int i = 1; i <= 50; ++i){
				midd = (ll + rr) / 2;
				if(solve(mid, midd).second > b)ll = midd;
				else rr = midd;
			}
			if(solve(mid, rr).first > a)l = mid;
			else r = mid;
		}
		solve(r, rr);
		printf("%lf\n",f[n] + r * a + rr * b);
	}
	return 0;
}

B Tourist Attractions

首先暴力n3或者n4枚举有70

正解也是枚举,但是有bitset优化

枚举中间两个点,计算贡献,减去非法贡献

非法贡献是什么,显然是构成了三元环,那么我们把他俩的bitset与一下,减去count即可

STL大法好,可惜我不会

code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<bitset>
using namespace std;
const int maxn = 1505;
int n;
long long ans = 0;
bitset <maxn> b[maxn];
char c[maxn];
int main(){
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i){
		scanf("%s",c + 1);
		for(int j = 1; j <= n; ++j)
		  if(c[j] == '1')b[i][j] = 1;
	}
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= n; ++j){
			if(b[i][j] == 0)continue;
			int r1 = b[i].count() - 1;
			int r2 = b[j].count() - 1;
			int r3 = (b[i]&b[j]).count();
			ans += r1 * r2 - r3;
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @   Chen_jr  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示