【LGR-122】T1 & T2 题解
T1
下面所说的做法来自于 dty(%%%%%%%%%)
注意到每一个数的绝对值是大于等于 Too large
,假设这个区间存在一个负数,那么当这个负数处于最中间的时候才会使的两边区间乘积的最大值最小,也就是说只要半个区间的乘积是大于 Too large
。再根据绝对值大于等于
对于暴力,其实也可以发现有着最大的乘积的区间一定是至少包含这个区间的一个端点的(分一下类很好证明)。所以直接以区间的左右端点为起点扫一下就知道了。
对于代码实现的时候有一些需要注意的点:
-
如果计算乘积的过程中乘积已经大于了
,那么直接退出即可 -
如果此时的乘积是小于
的,那么需要继续向后找,找到是否还存在负数,如果有,那么负负得正,一定会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
一眼树形
设
需要注意的是,这个方程中用到的
这样就完事了。
代码有些细节需要注意。
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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步