首页 > 其他分享 >DTOJ 2022-11-21 测试 题解

DTOJ 2022-11-21 测试 题解

时间:2022-11-21 20:45:06浏览次数:53  
标签:11 le 21 int 题解 ll long 蛋糕 max

测试成果

非常寄

35+56+0+8=99

基本上把能犯的错误都犯了

T1 记得 dp 数组初始化 \(-\infty\)!!!!

T2 记得认真暴搜,不要乱记录访问状态

T3 记得把调试删掉!!!!!

T4 记得开 long long !!

红日学长很会写题目名称,让我看着很想打原神(

可惜挂大分,上次题目名称是 arcaea 的时候也挂大分了

A 风与牧歌的城邦 (mondstadt)

DTOJ P6395

没有温迪的后果就是写不出第一题 \(\dots\)

题目大意

给定序列 \(\{a_n\},\{b_n\}\),保证 \(a_1, a_2, \dots, a_n\) 两两不同。

对于 \(\forall 1 \le l \le r \le n\),定义区间 \([l, r]\) 的权值如下:设 \(a_p = \max\{a_l, a_{l + 1}, \dots, a_r\}\),则 \([l, r]\) 的权值为 \(b_p\)。

你需要将 \(1 \sim n\) 划分为若干段,求每一段的权值之和的最大值。

对于所有测试数据,保证 \(1 \le n \le 5 \times 10 ^ 5\),\(1 \le a_i \le n\),\(- 10 ^ 9 \le b_i \le 10 ^ 9\),保证 \(a_1, a_2, \dots, a_n\) 是 \(1 \sim n\) 的一个排列。

题解

dp 方程不够优()

\(O(n^2)\) 做法

\(f_{i}\) 表示 \(1\sim i\) 最大值.

\(\displaystyle{f_i=\max_{prv_i\le j<i}\{f_j+w(j+1,i-1)\}}\)

其中 \(\displaystyle{w(L,R)=b_k,\max_{i\in[L,R]}\{a_i\}=a_k}\)

\(prv_i=\max_{k}\{a_k>a_i\}\)

这个不好优化,我们考虑调教式子

变成这样

\[f_i=\max_{j} \begin{cases} \begin{align*} &f_{prv_i}&,prv_i\ne 0\\ &\max_{prv_i\le k<i}\{f_k\}+b_i &,prv_i\ne0\\ &\max\{0,\max_{1\le k<i}\{f_k\}\}+b_i &,prv_i=0\\ \end{align*} \end{cases} \]

\(O(n\log n)\) 做法

单调栈处理 \(prv_i\),线段树处理 \(f_i\) 最大值

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e5+5;
const ll inf = 1e18;
int n,a[N],b[N];
int st[N],tp,prv[N];
ll f[N];
struct Sagiri
{
	int l,r;
	ll mx;
} t[N<<2];
#define ls (p<<1)
#define rs (p<<1)|1
void build(int p, int l, int r)
{
	t[p].l=l,t[p].r=r;
	if(l==r) { t[p].mx=-inf; return ; }
	int mid=(l+r)>>1;
	build(ls,l,mid),build(rs,mid+1,r);
	t[p].mx=max(t[ls].mx,t[rs].mx);
}
void change(int p, int x, ll v)
{
	if(t[p].l==t[p].r) { t[p].mx=v; return ; }
	int mid=(t[p].l+t[p].r)>>1;
	if(x<=mid) change(ls,x,v);
	else change(rs,x,v);
	t[p].mx=max(t[ls].mx,t[rs].mx);
}
ll query(int p, int l, int r)
{
	if(t[p].l==l and t[p].r==r) return t[p].mx;
	int mid=(t[p].l+t[p].r)>>1;
	if(r<=mid) return query(ls,l,r);
	else if(l>mid) return query(rs,l,r);
	else return max(query(ls,l,mid),query(rs,mid+1,r));
}
int main()
{
	scanf("%d",&n);
	for(int i=1; i<=n; i++) scanf("%d",&a[i]);
	for(int i=1; i<=n; i++) scanf("%d",&b[i]);
	for(int i=1; i<=n; i++)
	{
		while(tp and a[st[tp]]<a[i]) tp--;
		if(tp>0) prv[i]=st[tp];
		st[++tp]=i;
	}
	for(int i=1; i<=n; i++) f[i]=-inf;
	build(1,1,n);
	
	for(int i=1; i<=n; i++)
	{
		if(prv[i]) f[i]=f[prv[i]];
		if(i==1) f[i]=b[i];
		else if(prv[i]) f[i]=max(f[i],query(1,prv[i],i-1)+b[i]);
		else f[i]=max(f[i],max(0ll,query(1,1,i-1))+b[i]);
		change(1,i,f[i]);
	}
	printf("%lld\n",f[n]);
	return 0;
}

我只能说我为什么想不出来,甚至暴力写挂,呜呜呜 \(\dots\)

B 岩与契约的海港 (liyue)

DTOJ P6396

虽然有钟离,可是还是挂分了

题目大意

给定 \(n\) 个蛋糕,每块蛋糕有一个美味值 \(w_i\)。蛋糕的两面分别涂有一种奶油 \(a_i\), \(b_i\),奶油共有四种类型,分别以 \(\texttt{X}\),\(\texttt{Y}\),\(\texttt{Z}\),\(\texttt{W}\) 表示。

蛋糕 A 能叠放在蛋糕 B 上当且仅当蛋糕 A 底面的奶油与蛋糕 B 顶面的奶油是同一种。其中底面和顶面可以任意指定,即可以对蛋糕进行翻转。

你需要从 \(n\) 个蛋糕中选择若干个,并将它们以任意方向、任意顺序叠在一起。求所选蛋糕的美味度之和的最大值。

题解

很好转化成图论模型.

把 \(\texttt{W}\),\(\texttt{X}\),\(\texttt{Y}\),\(\texttt{Z}\) 看做四个点,把一个蛋糕看做一条边

我们就是要找一条路径,每一条边只经过一次,边权和的最大值.

注意到如果重边数大于 \(2\),可以在经过它的时候,多走一个来回.

所以最多少走一条边(一定是最小的那条)

于是对于每两个点重边,记录他边数的奇偶,边权和,边权最小值.

现在图中最多 \(12\) 条边,轻松暴搜完成.

可惜不知道为什么写挂了,测试完改改就过了,不知道错哪了(

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e5+5;
int n;
int sum[6][6],cnt[6][6],mn[6][6];
int tmp[6][6];
int vt[6];
int st[10],tp;
int dfs(int u, int cur)
{
	if(cur>13) return 0;
	st[++tp]=u;
	int res=0;
	for(int i=1; i<=4; i++) vt[i]=0;
	for(int i=1; i<=tp; i++) vt[st[i]]=1;
	for(int i=1; i<=4; i++) if(vt[i]) res+=sum[i][i];
	for(int i=1; i<=4; i++) for(int j=1; j<=4; j++) tmp[i][j]=0;
	for(int i=1; i<tp; i++)
	{
		int u=st[i],v=st[i+1];
		if(u>v) swap(u,v);
		tmp[u][v]++;
	}
	int flag=0;
	for(int i=1; i<=4; i++)
		for(int j=i+1; j<=4; j++)
		{
			if(tmp[i][j]>=3) flag=1;
			else if(tmp[i][j]==2 and cnt[i][j]<2) flag=1;
			else if(tmp[i][j]==2 and (cnt[i][j]&1)) res+=sum[i][j]-mn[i][j];
			else if(tmp[i][j]==2) res+=sum[i][j];
			else if(tmp[i][j]==1 and cnt[i][j]<1) flag=1;
			else if(tmp[i][j]==1 and (cnt[i][j]&1)) res+=sum[i][j];
			else if(tmp[i][j]==1) res+=sum[i][j]-mn[i][j];
		}
	if(flag) { tp--;  return 0; }
	for(int i=1; i<=4; i++)
	{
		if(u==i) continue;
		res=max(res,dfs(i,cur+1));
	}
	tp--; return res;
}
int main()
{	
	ios::sync_with_stdio(false); cin.tie(0);
	cin>>n;
	int w; string a,b;
	for(int i=1; i<=n; i++)
	{
		cin>>w>>a>>b;
		int u=a[0]-'W'+1,v=b[0]-'W'+1;
		if(u>v) swap(u,v); cnt[u][v]++,sum[u][v]+=w;
		if(mn[u][v]) mn[u][v]=min(mn[u][v],w);
		else mn[u][v]=w;
	}
	int ans=0;
	for(int i=1; i<=4; i++) ans=max(ans,dfs(i,1));
	printf("%d\n",ans);
	return 0;
}

C 雷与永恒的群岛 (inazuma)

DTOJ P6397

虽然刚打完稻妻任务,但是我没删调试,虽然是正解

题目大意

给定序列 \(\{a_{2n}\}\)。你需要选出 \(n\) 个位置 \(1 \le b_1 < b_2 < \dots < b_n \le 2n\),求 \(\gcd(a_{b_1}, a_{b_2}, \dots, a_{b_n})\) 的最大值。

对于所有测试数据,保证 \(1 \le n \le 10 ^ 5\),\(1 \le a_i \le 10 ^ {12}\)。

题解

\(O(na_i)\) 做法

枚举 \(\gcd\),看看够不够 \(n\) 个 \(\gcd\) 的倍数

随机化乱搞 \(O(\operatorname{can}\ AC)\) 做法

  1. 随机两个位置,求 \(gcd\),塞进一个 set 里
  2. set 里随机两个位置,求 \(gcd\),塞进 set 里

2 这个操作重复三次.

我也不知道为什么是对的,但是没有 2 可以构造出反例

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
int n,m,ng;
ll a[N<<1];
set<ll> st,st2;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int random(int l, int r)
{
	assert(r>=l);
	return uniform_int_distribution<>(l,r)(rng);
}
int main()
{
	scanf("%d",&n); m=n<<1;
	for(int i=1; i<=m; i++) scanf("%lld",&a[i]);
	int T=100;
	ll ans=0;
	for(int i=1; i<=T; i++)
	{
		int pos1=random(1,m),pos2=random(1,m);
		st.insert(__gcd(a[pos1],a[pos2]));
	}
	for(int t=1; t<=3; t++)
	{
		st2.clear();
		for(int u:st) for(int v:st) st2.insert(__gcd(u,v));
		for(int u:st2) st.insert(u);
	}
	for(ll d:st)
	{
		int cnt=0;
		for(int i=1; i<=m; i++) if(a[i]%d==0) cnt++;
		if(cnt>=n) ans=max(ans,d);
	}
	printf("%lld\n",ans);
	return 0;
}

标签:11,le,21,int,题解,ll,long,蛋糕,max
From: https://www.cnblogs.com/copper-carbonate/p/16913134.html

相关文章

  • AtCoder 题解集
    虽然暂时不知道会不会从XCPC中退役,但还是想把这个题解集给维护下去。\(created\;at\;2022/6/24\;by\;Roshin\)目录AGCARCABCABC138F.Coincidence(结论,数位DP)AB......
  • ### 52ed 2022/11/19 模拟赛总结37
    这次并没有认真打,但是有一些问题还是。。。真令人无语地暴露了出来反思本次暴力T2时,看到题目说运算过程全在无符号32位整数内,很高兴地冒死用了unsignedint,然后输入输......
  • ZR2448 题解
    题意给定一个长度为\(n\)的匹配的括号序列\(s\)。给出\(q\)组询问,每组询问形如:光标从\(s\)的第\(a\)个字符出发,使用一下三种操作:将光标移到左边的字符。将光......
  • [题解] CF1149D Abandoning Roads
    难得自己想出来一道3000分的题,虽然说考试的时候打挂了...首先先对较小的边缩点,然后求连通块内的最短路。显然,连通块内其实想怎么走就怎么走,但不能走较大的边。然后不同......
  • 11.21.3
    #include<stdio.h>#include<math.h>intmain(){ inti; for(i=10;i<1000;i++) {if(i>=10&&i<100&&pow(i%10,3)+pow(i/10,3)==i)printf("%d ",i); if(i>=100&&i<100......
  • delphi D11编程语言手册 学习笔记(P225-P343) OOP(面向对象)
      这本书可以在Delphi研习社②群256456744的群文件里找到.书名:Delphi11AlexandriaEdition.pdf●P139类是抽象的,变量是类的具现.类在定义时,只是......
  • 11.21.3
    #include<stdio.h>intji(inta[]);intmain(){ inta[4],b[3],c[3],d[3],e[3]; inti; for(i=0;i<4;i++) scanf("%d",&a[i]); b[0]=a[0];b[1]=a[1];b[2]=a[2]; c[......
  • 20221118-Python-初始函数
    1.函数的定义    2.函数的参数:    3.函数的返回值:    4.可变长度参数与任意参数 ......
  • 题解 LGP5380【[THUPC2019]鸭棋】
    postedon2021-06-0113:27:59|under题解|source给一种船新的做法,存棋子的位置而不是棋盘,我们只需要写一个生成棋子能移动到哪些位置的函数就可以了。#include<st......
  • 【221121-8】已知:正数x,y满足x平方*y=2.求:x平方+xy的最小值。
    ......