首页 > 其他分享 >10.5 杂题补做

10.5 杂题补做

时间:2023-10-07 19:33:58浏览次数:33  
标签:10.5 int tr mid add tag 杂题 first

T1 雷老师的正偏态分布

简要题意: 给出一个数组 \(a\) 要找一段 平均数 \(<\) 中位数的子集的方案 其中子集大小是奇数
其中 \(a_i\leq V\)
范围: \(n\leq 100\space V\leq 800\)

这里有两个思路

  • 1 枚举平均数 锁定中位数 比较难找 可以抛弃
  • 2 枚举中位数 锁定平均数

我们发现第二种很好做
只需要把数组排序 然后 \(O(n)\) 枚举一个中位数
然后再 \(O(n)\) 枚举以这个数为中心左右找几个数 他们的和小于这个中位数的某个倍数
然后这个东西前后做一次背包和前缀和就行了

时间复杂度 \(O(n^3V)\) 空间复杂度 \(O(n^3V)\)

时间(理论)是过得去的 实际真的能过去 但是空间炸了
于是要优化空间
正着做的背包顺序做很简单
倒着做的背包考虑一下倒背包很快解决

后面就是一些卡常问题

AC code

#include<bits/stdc++.h>
#pragma GCC optimize (1)
#pragma GCC optimize (2)
#pragma GCC optimize (3,"Ofast","inline")
#define ll long long
#define N 105
#define M N*800
using namespace std;
const int mod = 998244353;
int n,m,sum;
int ans;
int a[N],b[N];
int f[N][M],f1[N][M],g[N][M];
void add(int &a,int b)
{
	a=a+b>mod?a+b-mod:a+b;
}
void solve(int l,int r)
{
	int mid=(a[l]+a[r])/2;
	for(int i=1;i<=min(l,n-r+1);i++)
		for(int j=0;j<i*mid*2;j++)
			add(ans,1ll*f1[i][j]*g[i][i*mid*2-j-1]%mod);
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),sum+=a[i];
	sort(a+1,a+1+n);
	f[0][0]=g[0][0]=1;
	for(int i=1;i<=n;i++)
		for(int j=n;j>=1;j--)
		{
			for(int k=sum;k>=a[i];k--)
				add(g[j][k],g[j-1][k-a[i]]);
		}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			for(int k=sum;k>=a[i];k--)
				add(g[j][k],mod-g[j-1][k-a[i]]);
		}
		solve(i,i);
		for(int j=n;j>=1;j--)
		{
			for(int k=sum;k>=a[i];k--)
				add(f[j][k],f[j-1][k-a[i]]);
		}
		f1[0][0]=f[0][0];
		for(int j=1;j<=n;j++)
			for(int k=1;k<=sum;k++)
				f1[j][k]=(f[j][k]+f1[j][k-1])-(f[j][k]+f1[j][k-1]>mod?mod:0);
	}
	printf("%d",ans);
	return 0;
}

T2 假期计划Ⅱ

原题: 传送门
纯纯毒瘤题目
题意:给出一个稠密图 \(n\) 个点 \(n^2\) 条边 每次删掉一条边 求 \(1\to n\) 走 \(k\) 条边的最短路
\(n\leq 300\space k\leq 8\)

只能说很毒
首先这种删边肯定很不好做 考虑时间倒流加边
正解是折半 大分类
维护 :
\(f_{i,j}\) 表示从 \(1\) 走 \(j\) 条边到 \(i\) 的最短路 其中 \(j\leq 4\)
\(g_{i,j}\) 表示从 \(i\) 走 \(j\) 条边到 \(n\) 的最短路 其中 \(j\leq 4\)
\(dp_{i,j,k}\) 表示从 \(i\) 走 \(k\) 条边到 \(j\) 的最短路 其中 \(k\leq 2\)

\(f,g,dp\) 的更新是 \(O(n)\) 的

总时间复杂度 \(O(n^3)\) 可以通过

但是不想写大分类怎么办(((

直接考虑分层图 spfa !
总共有 \(nk\) 个点 \(n^2k\) 条边
总时间复杂度应该是 \(O(n^4k)\) 直接升天
但是它就是卡过去了
假代码就不放了 (((

T3 惊蛰

写的最痛心的一题
传送门
这题一眼 dp 思考出最简单的 dp 不难
考虑 \(f_{i,j}\) 表示第 \(i\) 个时刻花 \(j\) 精力去做
滚一个后缀最小值就可以优化成 \(O(n^2)\) 的了
最重要的是考虑到这道题的单调性
如果当前分界点是 \(pos\) 那么这个位置前后一定是成单调上升的
原因就在于加上的数是单调上升的
这样经过多重优化可以简化代码
这里放出优化到最简洁的 \(O(n^2)\) 代码

#include<bits/stdc++.h>
#define ll long long
#define N 10005
using namespace std;
int n,m,a[N],b[N];
ll f[N];
int main()
{
//	freopen("c.in","r",stdin);
//	freopen("c.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),b[i]=a[i];
	sort(b+1,b+1+n);
	int len=unique(b+1,b+1+n)-b-1;
	f[len+1]=1e17;
	for(int i=1;i<=n;i++)
	{
		int pos=lower_bound(b+1,b+1+len,a[i])-b;
		for(int j=1;j<pos;j++)
			f[j]=f[j]+m;
		for(int j=pos;j<=n;j++)
			f[j]=f[j]+b[j]-a[i];
		int first=lower_bound(f,f+1+pos-1,f[pos])-f;
		for(int j=first;j<pos;j++)
			f[j]=f[pos];
	}
	cout<<f[1];
	return 0;
}

到这一步 也就是最难的一步 要把 dp 数组拍到线段树上面
第一个 for 区间加 很好解决
第二个要加上一个数组 不是很好搞 这个后面说
第三个是推平 容易写
难点就在于 在 \(1\to pos\) 中找第一个比 \(f[pos]\) 大的数
这里考虑记下当前线段树最左边的端点 然后二分即可

因此 增加一个数组 记录一下系数和映射的数即可

调吐了

我写的估计比较丑和冗杂

AC code

#include<bits/stdc++.h>
#define ll long long
#define N 1000005
using namespace std;
int n,m;
ll a[N],b[N];
struct tree{
	ll add,cov,tag,first,v;
	// 增加 覆盖 增加系数 最右边的值 
}tr[N*4];
void Pushup(int x)
{
	tr[x].first=tr[x*2].first;
}
void Pushdown(int x)
{
	if(tr[x].cov)
	{
		tr[x*2].cov=tr[x*2+1].cov=tr[x].cov;
		tr[x*2].add=tr[x*2+1].add=tr[x*2].tag=tr[x*2+1].tag=0;
		tr[x*2].first=tr[x*2+1].first=tr[x].cov;
		tr[x].cov=0;
	}
	if(tr[x].add)
	{
		tr[x*2].add+=tr[x].add,
		tr[x*2+1].add+=tr[x].add;
		tr[x*2].first+=tr[x].add;
		tr[x*2+1].first+=tr[x].add;
		tr[x].add=0;
	}
	if(tr[x].tag)
	{
		tr[x*2].tag+=tr[x].tag,
		tr[x*2+1].tag+=tr[x].tag;
		tr[x*2].first+=tr[x].tag*b[tr[x*2].v];
		tr[x*2+1].first+=tr[x].tag*b[tr[x*2+1].v];
		tr[x].tag=0;
	}
}
void updata(int l,int r,int L,int R,int x,ll v) 
{
	if(l>R||r<L) return;
	if(l>=L&&r<=R)
	{
		tr[x].add+=v;
		tr[x].first+=v;
		return;
	}
	int mid=(l+r)/2;
	Pushdown(x);
	updata(l,mid,L,R,x*2,v);
	updata(mid+1,r,L,R,x*2+1,v);
	Pushup(x);
}
void modify(int l,int r,int L,int R,int x) 
{
	if(l>R||r<L) return;
	if(l>=L&&r<=R)
	{
		tr[x].tag++;
		tr[x].first+=b[tr[x].v];
		return;
	}
	int mid=(l+r)/2;
	Pushdown(x);
	modify(l,mid,L,R,x*2);
	modify(mid+1,r,L,R,x*2+1);
	Pushup(x);
}
ll query(int l,int r,int L,int x) 
{
	if(l==r) return tr[x].first;
	Pushdown(x);
	int mid=(l+r)/2;
	if(L<=mid) return query(l,mid,L,x*2);
	else return query(mid+1,r,L,x*2+1);
}
void cover(int l,int r,int L,int R,int x,ll v)
{
	if(l>R||r<L) return;
	if(l>=L&&r<=R)
	{
		tr[x].add=tr[x].tag=0;
		tr[x].cov=tr[x].first=v;
		return;
	}
	Pushdown(x);
	int mid=(l+r)/2;
	cover(l,mid,L,R,x*2,v);
	cover(mid+1,r,L,R,x*2+1,v);
	Pushup(x);
}
void access(int l,int r,int L,int R,int x,ll v)
{
	if(l>R||r<L) return;
	if(l==r)
	{
		tr[x].first=min(tr[x].first,v);
		return ;
	}
	int mid=(l+r)/2;
	Pushdown(x);
	if(mid+1>=R)
		access(l,mid,L,R,x*2,v);
	else
	{
		if(tr[x*2+1].first>=v)
		{
			cover(mid+1,r,mid+1,R,x*2+1,v);
			access(l,mid,L,R,x*2,v);
		}
		else
			access(mid+1,r,L,R,x*2+1,v);
	}
	Pushup(x);
}
void build(int l,int r,int x)
{
	if(l==r)
	{
		tr[x].first=0;
		tr[x].v=l;
		return;
	}
	int mid=(l+r)/2;
	build(l,mid,x*2);
	build(mid+1,r,x*2+1);
	tr[x].v=tr[x*2].v;
}
int main()
{
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]),b[i]=a[i];
	sort(b+1,b+1+n);
	int len=unique(b+1,b+1+n)-b-1;
	build(1,len,1);
	for(int i=1;i<=n;i++)
	{
		int pos=lower_bound(b+1,b+1+len,a[i])-b;
		updata(1,len,1,pos-1,1,m);
		updata(1,len,pos+1,len,1,-a[i]);
		modify(1,len,pos+1,len,1);
		ll val=query(1,len,pos,1);
		access(1,len,1,pos,1,val);
	}
	printf("%lld",query(1,len,1,1));
	return 0;
}

这个题评蓝 可以说是蓝题巅峰了

标签:10.5,int,tr,mid,add,tag,杂题,first
From: https://www.cnblogs.com/g1ove/p/17747274.html

相关文章

  • 2023.10.6 若干杂题
    P1552[APIO2012]派遣每个点作为管理者,只需要计算其子树内,最多有多少个人加起来不大于\(M\),考虑维护前\(k\)小的元素。可以使用左偏树合并。然而其实可以平衡树合并,每次在平衡树上二分。P2685[TJOI2012]桥首先,Boss镇守的桥一定是最短路上的边,使得我们不得不改变线路。......
  • 2023.10.5测试
    \[\text{NOIP模拟赛-2023.10.5}\]T1魔法少女定义\(f(i)\)为\(i\)所有约数的异或和,求\(f(1)\simf(n)\)的异或和\(1\leqn\leq10^{14}\)容易想到枚举约数然后计算出约数出现的次数并对答案做贡献,复杂度\(\mathcal{O}(n)\)发现约数\(x\)出现的次数即\(\left\lfloor......
  • 【GJOI 2023.10.5 T1】 雷老师的正偏态分布
    雷老师的正偏态分布题意:给出一个长度为\(n\)的\(a\)数组,其中\(1\lea_i\leV,1\lei\len\)。统计其中的满足平均数严格小于中位数且大小为奇数的子集数量,\(n\le100,V\le800\),时限\(4\)s。输入:510127910输出:8首先,可以考虑排序,保证一个子集中小......
  • 10.5 认识XEDParse汇编引擎
    XEDParse是一款开源的x86指令编码库,该库用于将MASM语法的汇编指令级转换为对等的机器码,并以XED格式输出,目前该库支持x86、x64平台下的汇编编码,XEDParse的特点是高效、准确、易于使用,它可以良好地处理各种类型的指令,从而更容易地确定一段程序的指令集。XEDParse库可以集成到许多不......
  • 2023.10.5
    A记\(\displaystylef(i)=\oplus_{d|i}d\),求\(\displaystyle\oplus_{i=1}^{n}f(i)\).\(n\le10^{14}\).考虑一个数是否出现计数次,对\(\lfloor\frac{n}{x}\rfloor\)整除分块,查询区间异或和即可。点击查看代码#include<bits/stdc++.h>#definelllonglongusingnames......
  • 2023.10.5——每日总结
    学习所花时间(包括上课):0h代码量(行):0行博客量(篇):1篇今天,上午学习+休息,下午学习+休息;我了解到的知识点:1.Maven;2.SpringBoot;明日计划:学习+休息......
  • GJOI 2023.10.5 T2 假期计划Ⅱ
    GJOI2023.10.5T2假期计划Ⅱ题意:给出一个有\(n\)个点的有向图,每点到另一点都有一条有向边,边有权值。现有\(n^2\)次操作,每次会删去一些边,问每次删去后从\(1\)号点到\(n\)号点经过恰好\(k\)条边的最短路,若无法到达输出\(-1\)。\(n\le300,k\le8\)输入:34104......
  • 10.5算法
    对称二叉树给你一个二叉树的根节点root,检查它是否轴对称。 示例1:输入:root=[1,2,2,3,4,4,3]输出:true示例2:输入:root=[1,2,2,null,3,null,3]输出:false 提示:树中节点数目在范围[1,1000]内-100<=Node.val<=100 /** * Definition for a binary tree......
  • PowerBuilder编程新思维10.5:外传2(PowerPlume下一代开发解决方案)
    万里归来年愈少 PowerBuilder编程新思维10.5:外传2(PowerPlume下一代解决方案) 前言今天我们就来盘点一下,PB下一代开发的所有技术可能性。所谓下一代开发技术,就是指脱离或半脱离PBVM的应用开发技术,主要指后端。 后端技术汇总  前端PB+JSON前端PB+BLOBWEB后端P......
  • 杂题选记
    杂题选记AStatement给定一个长度为\(n\)的单调不降的整数数列\(A\)。有\(q\)次相互独立的询问,每次询问给定\(l,r\),从时刻\(0\)起,每个时刻对于\(\foralli\in\left[l,r\right)\)且\(A_i\textcolor{red}{\lt}A_{i+1}\),令\(A_i\getsA_i+1\)。问最少经过多少时刻......