首页 > 其他分享 >【LGR-122】T1 & T2 题解

【LGR-122】T1 & T2 题解

时间:2022-10-05 14:35:08浏览次数:74  
标签:int 题解 void flag 122 template LGR dp getchar

T1

下面所说的做法来自于 dty(%%%%%%%%%)

注意到每一个数的绝对值是大于等于 \(2\) 的,那么就可以发现一个性质:当一个区间长度为 \(len\) 时,如果 \(len\ge 62\),那么这个区间的答案一定会是 Too large,假设这个区间存在一个负数,那么当这个负数处于最中间的时候才会使的两边区间乘积的最大值最小,也就是说只要半个区间的乘积是大于 \(2^{30}\),那么这个区间就是 Too large。再根据绝对值大于等于 \(2\) 这一条件,可以得知需要计算答案的区间长度一定是在 \(62\) 以内的。这样每一次询问的规模就被降到了 \(1e2\) 以内,暴力处理即可。

对于暴力,其实也可以发现有着最大的乘积的区间一定是至少包含这个区间的一个端点的(分一下类很好证明)。所以直接以区间的左右端点为起点扫一下就知道了。

对于代码实现的时候有一些需要注意的点:

  • 如果计算乘积的过程中乘积已经大于了 \(2^{30}\),那么直接退出即可

  • 如果此时的乘积是小于 \(-2^{30}\) 的,那么需要继续向后找,找到是否还存在负数,如果有,那么负负得正,一定会 Too large。如果不进行这个处理,很有可能在负数的时候炸了 long long

Code

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
#define int long long
using namespace std;
template<typename T> void read(T &k)
{
	k=0;T flag=1;char b=getchar();
	while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
	while (isdigit(b)) {k=k*10+b-48;b=getchar();}
	k*=flag;
}
template<typename T> void write(T k) {if (k<0) {putchar('-'),write(-k);return;}if (k>9) write(k/10);putchar(k%10+48);}
template<typename T> void writewith(T k,char c) {write(k);putchar(c);}
const int _SIZE=2e5;
int n,q,a[_SIZE+5];
int res=1,temp=1;
signed main()
{
	//freopen("T1ex2.in","r",stdin);
	//freopen("T1ex2.ans","w",stdout);
	read(n),read(q);
	for (int i=1;i<=n;i++) read(a[i]);
	for (int i=1;i<=q;i++)
	{
		int opt,x,y;read(opt),read(x),read(y);
		if (opt==1) a[x]=y;
		else
		{
			if (y-x+1>=65) {puts("Too large");continue;}
			temp=1,res=1;
			bool flag=0;
			for (int i=x;i<=y;i++)
			{
				temp*=a[i];
				if (temp<-(1ll<<30)) 
				{
					for (int j=i+1;j<=y;j++) if (a[j]<0) {puts("Too large");flag=1;break;}
					break;
				}
				if (temp>(1ll<<30)) {puts("Too large");flag=1;break;}
				res=max(res,temp);
			}
			if (flag) continue;
			temp=1;
			for (int i=y;i>=x;i--)
			{
				temp*=a[i];
				if (temp<-(1ll<<30)) 
				{
					for (int j=i-1;j>=x;j--) if (a[j]<0) {puts("Too large");flag=1;break;}
					break;
				}
				if (temp>(1ll<<30)) {puts("Too large");flag=1;break;}
				res=max(temp,res);
			}
			if (!flag) writewith(res,'\n');
		}
	}
	return 0;
}

T2

一眼树形 \(\text{DP}\)。

设 \(dp[i][j]\) 表示以 \(i\) 为根节点的子树中删除掉 \(j\) 个节点的最小代价,那么可以有这样的转移方程:

\[dp[i][j]=\min\limits_{s\in son[i]}\{dp[i][k]+dp[s][j-k]\} \]

需要注意的是,这个方程中用到的 \(dp[s][j-k]\) 一定是当前儿子删的只剩儿子这一个节点的,也就是说 \(dp[i][j]\) 没办法更新到 \(dp[i][size-1]\) 这一个位置,即没法把这个子树删的只剩子树的根,所以需要额外补一个用于转移 \(dp[i][size-1]\) 的方程:

\[dp[i][size-1]=\min\{dp[i][j]+f[size-j]\} \]

这样就完事了。

代码有些细节需要注意。

Code

#include<bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof a)
#define int long long
using namespace std;
template<typename T> void read(T &k)
{
	k=0;T flag=1;char b=getchar();
	while (!isdigit(b)) {flag=(b=='-')?-1:1;b=getchar();}
	while (isdigit(b)) {k=k*10+b-48;b=getchar();}
	k*=flag;
}
template<typename T> void write(T k) {if (k<0) {putchar('-'),write(-k);return;}if (k>9) write(k/10);putchar(k%10+48);}
template<typename T> void writewith(T k,char c) {write(k);putchar(c);}
const int _SIZE=5e3;
int n;
struct EDGE{
	int nxt,to;
}edge[(_SIZE<<1)+5];
int tot,head[_SIZE+5];
void AddEdge(int x,int y) {edge[++tot]=(EDGE){head[x],y};head[x]=tot;}
int f[_SIZE+5],dp[_SIZE+5][_SIZE+5],siz[_SIZE+5];
void dfs(int x,int fa)
{
	dp[x][0]=0,siz[x]=1;
	for (int i=head[x];i;i=edge[i].nxt)
	{
		int twd=edge[i].to;
		if (twd==fa) continue;
		dfs(twd,x);
		for (int j=siz[x]+siz[twd]-1;j>0;j--)
			for (int k=max(j-siz[x],1ll);k<=j && k<siz[twd];k++)
				dp[x][j]=min(dp[x][j],dp[twd][k]+dp[x][j-k]);
		siz[x]+=siz[twd];//如果把这句放在dfs(twd,x)之后,就表示x删点也删到了twd内,而k又再次计算了这一部分,所以应该算完了dp数组才更新siz[x]
	}
	for (int j=0;j<siz[x]-1;j++)
		dp[x][siz[x]-1]=min(dp[x][siz[x]-1],dp[x][j]+f[siz[x]-j]);
}
signed main()
{
	mem(dp,0x3f);
	read(n);
	for (int i=2;i<=n;i++) read(f[i]);
	for (int i=1;i<n;i++)
	{
		int u,v;read(u),read(v);
		AddEdge(u,v);AddEdge(v,u);
	}
	dfs(1,0);
	writewith(dp[1][siz[1]-1],'\n');
	return 0;
}

标签:int,题解,void,flag,122,template,LGR,dp,getchar
From: https://www.cnblogs.com/hanx16msgr/p/16755519.html

相关文章

  • 组态软件报警问题解决
    作为工业自动化领域的从业者,经常会使用各种组态软件,近期作者在使用业界鼎鼎大名的组态软件IFix过程中就遇到了一个小case,现在分享给大家。众所周知,IFix在运行过程中报警会......
  • 【题解】P3583 [POI2015] KWA
    模拟赛出这道题???还好赛时乱搞做出来了(/hanxlinkDescription定义一个数\(n\)的拆分为:将\(n\)表示为若干个不同的正整数的平方和。令\(k(n)\)为\(n\)的拆分中最......
  • CF 547D. Mike and Fish 题解
    Solution1二分图染色显然这题是构造染色方案,于是我们考虑将矩阵转化成图进行染色。结论:将同一行的点两两配对,将同一列的点两两配对,形成的一定是二分图。证明:由于每......
  • P4572 题解
    前言题目传送门!更好的阅读体验?双倍经验:P3554(数据坑一点)。简要题意可以看P3554。思路:二分答案+树形DP。思路答案显然具有单调性,所以考虑二分答案。\(\operatorna......
  • P3226 [HNOI2012]集合选数 题解
    纪念一下30紫and500AC首先先膜拜一下神仙出题人,这题太神仙了。题意:要构造一个集合,使得$x\inA$,满足$2x\notinA$且$3x\notinA$,求\(\{1,2,\ldots,n\}\)......
  • 【Ynoi2009】 rla1rmdq 题解 (离线分块 + 线性空复处理)
    洛谷传送门分块。Solution看到是区修区查,还有时限,不难想到是分块,根号复杂度。然后看到空间复杂度,需要离线下来转为线性复杂度。考虑如何分块。观察操作性质,发现节点......
  • 「CF1455G」Forbidden Value 题解 (DP,线段树合并)
    题目简介已知初始值\(x=0\),给定下面\(2\)种命令:set\(y\)\(v\),令\(x=y\),或花费\(v\)元钱删除该命令;if\(y\)...end,如果\(x==y\),执行if...end中的命令,否则跳......
  • [题解]洛谷 P4930、BZOJ 4221
    洛谷P4930考虑\(\varphi\)有什么性质,设\(x\)的质因数分解为\(\prod_{i=1}^mp_i^{a_i}\),那么\(n=\varphi(x)=\prod_{i=1}^m(p_i-1)\times\prod_{i=1}^mp_i^{a_i-1......
  • 「ROIR 2021 Day 1」题解
    loj有原题。别问为什么没T4,问就是不会,等以后来补。T1-两台机器设两台机子分别为\(a,b\),分\(4\)种情况:只用\(a\),只用\(b\),先\(a\)后\(b\),先\(b\)后\(a\),判断......
  • Windows下CLion中文乱码问题解决
    (目录)原因分析Windows内部采用UTF-16编码,对于中文操作系统使用GBK编码,但是CLion默认文本编码为UTF-8,当编码不一致时,就会造成输出乱码,甚至编译不通过。解决方案当然,对于......