首页 > 其他分享 >2021 ICPC 上海 DEHI

2021 ICPC 上海 DEHI

时间:2023-08-15 20:14:16浏览次数:38  
标签:ab int dfrac ll mid long ICPC DEHI 2021

2021 ICPC 上海 DEHI

链接:The 2021 ICPC Asia Shanghai Regional Programming Contest

D. Strange Fractions

题意:给你\(p,q\),让你找正整数\(a,b\),使得\(\dfrac{p}{q} = \dfrac{a}{b}+\dfrac{b}{a}\)。如果不存在,输出\(0\) \(0\)。

思路:简单数学。推柿子+\(\gcd\)

因为有\(\dfrac{p}{q} = \dfrac{a}{b}+\dfrac{b}{a}\),我们通分一下就有:\(\dfrac{p}{q} = \dfrac{a^2+b^2}{ab}\)

于是:

\[\dfrac{p}{q} = \dfrac{a^2+b^2}{ab} = \dfrac{a^2+b^2+2ab-2ab}{ab} = \dfrac{(a+b)^2-2ab}{ab} = \dfrac{(a+b)^2}{ab}-2 \]

我们移项得:

\[\dfrac{p}{q}+2 = \dfrac{(a+b)^2}{ab} \]

\[\dfrac{p+2q}{q} = \dfrac{(a+b)^2}{ab} \]

那么:

\[p+2q = (a+b)^2 \]

\[q = ab \]

我们发现,2个方程2个未知数,可以解了。我直接求根公式算的。

接下来就是求解过程了:

\[a+b = \sqrt{p+2q} \]

\[b = \sqrt{p+2q}-a \]

然后把\(b\)代入得:

\[ab = a(\sqrt{p+2q}-a) = q \]

\[-a^2+a\sqrt{p+2q}-q = 0 \]

\[a = \dfrac{-\sqrt{p+2q}\pm\sqrt{p+2q-4q}}{-2} \]

\[b = \dfrac{q}{a} \]

一开始以为这样就搞定了,很愉快的\(submit\)了,然后\(wa...\)

思考了一会,发现\(p = 2,q = 1\)和\(p = 4,q = 2\)的结果不一样。好的,它可能不是最简的。那么上下同除\(\gcd\)化为最简之后在做,就可以\(ac\)了。

注意:

  1. 可能不是最简分数,注意先化简
  2. \(sqrt\)有精度问题,我们用二分解决
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;

bool check(ll x)
{
	if(x < 0)	return false;
	ll l = 0, r = x;
	while(l < r)
	{
		ll mid = (l + r) >> 1;
		if(mid * mid >= x)	r = mid;
		else l = mid + 1;
	}
	if(l * l == x)
		return true;
	else return false;

}
ll sq(ll x)
{
	ll l = 0, r = x;
	while(l < r)
	{
		ll mid = (l + r) >> 1;
		if(mid * mid >= x)	r = mid;
		else l = mid + 1;
	}
	return l;
}
ll p, q;

void solve()
{
	cin>>p>>q;
	ll g = __gcd(p, q);
	p /= g, q /= g;
	if(!check(2 * q + p) || !check(2 * q + p - 4 * q))
	{
		cout<<"0 0\n";
		return;
	}
	ll a1 = (-sq(2 * q + p) + sq(2 * q + p - 4 * q)) / -2;
	ll a2 = (-sq(2 * q + p) - sq(2 * q + p - 4 * q)) / -2;

	if(a1 >= 1 && q % a1 == 0 && q / a1 >= 1)
		cout<<a1<<" "<<q / a1;
	else if(a2 >= 1 && q % a2 == 0 && q / a2 >= 1)
		cout<<a2<<" "<<q / a2;
	else
		cout<<"0 0";
	cout<<'\n';
}


int main()
{
	ios::sync_with_stdio(false);	cin.tie(nullptr);cout.tie(nullptr);
	int tc;	cin>>tc;
	for(int i = 1; i <= tc; i++)
		solve();
	return 0;
}

E.Strange_Integers

题意:给你\(n\)个数的序列和一个参数\(k\),你从这\(n\)个数里面选\(m\)个,使得任意两个的差值的绝对值都大于等于\(k\)。问你最多可以选多少个数。

思路:\(sort\)+贪心

我们先排序,然后\(for\)一遍处理出来前缀最大值,然后直接贪心即可(能选就选)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int a[N],pre[N];
int n,m;
int main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m;
	for(int i = 1; i <= n; i++)
		cin>>a[i];
	sort(a+1,a+1+n);
	for(int i = 1; i <= n; i++)
		pre[i] = max(pre[i-1],a[i]);
	if(m==0){
		cout<<n<<endl;
		return 0;
	}
	int now = a[1];
	int cnt = 1;
	for(int i = 2; i <= n; i++)
	{
		if(pre[i]-now>=m)cnt++,now = pre[i];
	}
	cout<<cnt<<endl;
	return 0;
}

H.Life is a Game

题意:给你\(n\)个点\(m\)条边的无向图。每个点有点权,每条边也有边权。我们有一个初始能量值,每经过一个点,可以获得当前点的点权,但是要经过一条边,需要我们当前的能力值大于这个边的边权才能走。给你起点和初始能量值,问你能量值最大可以是多少?

思路:\(Kruskal\)重构树+树上倍增

由于有边权的限制,当能量值大于当前边权才能走。那么对于一条简单路径,限制我们的是这条路径上的最大值。我们考虑最优策略,如果有多条路,肯定走最大值越小的路。那么想让最大值最小,考虑\(Kruskal\)重构最小生成树。重构完之后,任意两点的\(lca\)就是这个路径上的最大值了。

我一开始的思路是:从当前给出的节点往上走,如果当前的值大于等于限制,我们就可以获得这个子树的所有点的权值。但是\(T7\)了。考虑最坏的情况,二叉树退化成链,这样的话,就是跑的暴力了,肯定是会\(T\)的。那怎么办呢?

因为我们建的是\(Kruskal\)重构树,是个大根堆,考虑预处理出每个点往上跳\(2^j\)步的花费。这里花费是指【要跳到的节点的限制-当前节点子树的权值和】。也就是,当前已经可以走到这里了,那么以当前节点为根的子树的权值我都可以得到了,用我要跳到的点的限制-当前获得的,就是我们的额外的花费。我们用这个花费和\(k\)去比,如果\(\le k\)小就可以往上跳,直到不能跳了为止。那么答案就是你能跳到的点的权值和+初始值\(k\)。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define int long long 
using namespace std;
typedef long long ll;
const int N = 4e5+10, M = 5e5+10;
const int LOGN = 20;
struct Node
{
	int x,y,v;
}a[M+1];

int n,m,q,now,val[N],dep[N],faa[N];
vector<int>e[N];
int ls[N],rs[N];
int sum[N];
int f[N][LOGN+2],cost[N][LOGN+2];
int c[N];//以i为根的子树的权值和

//////////////////////////////DSU//////////////////////////////////////
struct Dsu {
	int fa[N];
	void init(int x) {for(int i = 1;i<=x;i++) fa[i] = i;}
	int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
	void merge(int x, int y) {
		int u = find(x), v = find(y);
		if(u == v) return;
		fa[u] = v;
	}
}dsu;
/////////////////////////Kruskal////////////////////////////////////

void kruskalRebuildTree()
{
	dsu.init(2*n-1);
	sort(a+1, a+1+m, [](const Node& x, const Node& y) {
		return x.v < y.v;//重构最小生成树
	});
	now = n;
	for(int i = 1;i<=m;i++) {
		ll u = dsu.find(a[i].x), v = dsu.find(a[i].y), w = a[i].v;
		if(u != v) {
			val[++now] = w;
			c[now] = c[u]+c[v];
			cost[u][0] = val[now] - c[u];
			cost[v][0] = val[now] - c[v];
			f[u][0] = f[v][0] = now;
			dsu.merge(u, now);
			dsu.merge(v, now);
			ls[now] = u;
			rs[now] = v;
		}
	}
}


////////////////////////////Main///////////////////////////////////
signed main()
{
	ios::sync_with_stdio(false);	cin.tie(nullptr);cout.tie(nullptr);

	cin>>n>>m>>q;
	for(int i = 1;i<=n;i++)cin>>c[i];
	for(int i = 1;i<=m;i++)
	{
		cin>>a[i].x>>a[i].y>>a[i].v;
	}
	kruskalRebuildTree();
	
	for(int j = 1;j<=LOGN;j++)
	{
		for(int u = 1;u<=now;u++)
		{
			f[u][j] = f[f[u][j-1]][j-1];
			cost[u][j] = max(cost[u][j-1],cost[f[u][j-1]][j-1]);
		}
	}
	while(q--)
	{
		int x, k;
		cin>>x>>k;
		
		for(int j = LOGN;j>=0;j--)
		{
			if(cost[x][j]<=k&&f[x][j])x = f[x][j];
		} 
		cout<<c[x]+k<<"\n";
	}
		
	return 0;
}

I.Steadily Growing Steam

题意:我们有\(n\)张卡片,每张卡片有自己的权值和点数。让你从这\(n\)张卡片里面选任意张,然后你可以令其中至多\(k\)张卡片的点数翻倍。之后我们把这选出来的卡片分成2组,使得这两组的点数一样。问:满足上述条件,两组的权值和最大可以是多少?

思路:\(DP\)(背包问题)

我们考虑定义\(dp\)数组,很容易想到定义为\(f[i][j][k]\):表示前\(i\)个物品,两组卡片点数差值为\(j\),使用了\(k\)次翻倍的权值和的最大值。但是物品数有\(100\),点差值在\(-1300\)到\(1300\),需要开到\(2600\),次数\(100\),那么就需要开到\(100*2600*100\)的数组。并且点数的差值有负数存在,那么我们需要一个偏移量,避免负数下标。定义\(1300\)为\(0\)(即偏移量为\(1300\)),数组从\(0\),到\(2600\),就能表示\(-1300\)到\(1300\)所以数了。我们第一维还可以考虑滚动数组优化。

考虑状态的转移:

  1. 不加入第\(i\)张牌,那么\(f[i][j][k] = f[i-1][j][k]\)

  2. 加入第\(i\)张牌:

    滚动数组优化:\(i\&1\)表示上一轮的。

    1. 不用魔法翻倍:

      考虑放在左边:\(if(j-w[i]\ge 0) f[i\& 1][j][k] = max(f[i \& 1][j][k],f[(i-1) \& 1][j-w[i]][k]+v[i])\)

      考虑放在右边:\(if(j+w[i]<=2600)f[i\& 1][j][k] = max(f[i\& 1][j][k],f[(i-1)\& 1][j-w[i]][k]+v[i])\)

    2. 考虑用魔法翻倍:

      考虑放在左边:\(if(j-2*w[i]>=0 \&\&k >0)f[i\& 1][j][k] = max(f[i\& 1][j][k],f[(i-1)\& 1][j-2*w[i]][k-1]+v[i])\)

      考虑放在右边:\(if(j+2*w[i]<=2600\&\&k>0)f[i\& 1][j][k] = max(f[i\& 1][j][k],f[(i-1)\& 1][j+2*w[i]][k-1]+v[i])\)

最后因为要求两边点数一样,那么差值就是\(0\),我们规定的偏移量是\(1300\),那么答案就是在\(1300\)处的值。

注意:记得初始化为-INF。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f[2][2610][110];
ll v[110], w[110];
ll n, m;


int main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>m;
	for(int i = 1;i <= n; i++)
		cin>>v[i]>>w[i];
	for(int i = 0;i <= 1;i ++)
		for(int j = 0;j <= 2600; j++)
			for(int k = 0;k <= m; k++)
				f[i][j][k] = -1e18;
	f[0][1300][0] = f[1][1300][0] = 0;

	for(int i = 1;i <= n;i++)
	{
		for(int j = 0;j <= 2600; j++)
		{
			for(int k = 0; k <= m; k++)
			{
				f[i&1][j][k] = max(f[i&1][j][k],f[(i-1)&1][j][k]);
				if(j-w[i]>=0)f[i&1][j][k] = max(f[i&1][j][k],f[(i-1)&1][j-w[i]][k]+v[i]);
				if(j+w[i]<=2600)f[i&1][j][k] = max(f[i&1][j][k],f[(i-1)&1][j+w[i]][k]+v[i]);
				if(j-2*w[i]>=0&&k>0)f[i&1][j][k] = max(f[i&1][j][k],f[(i-1)&1][j-2*w[i]][k-1]+v[i]);
				if(j+2*w[i]<=2600&&k>0)f[i&1][j][k] = max(f[i&1][j][k],f[(i-1)&1][j+2*w[i]][k-1]+v[i]);
			}
		}
	}
	ll ans = 0;
		for(int j = 0;j<= m;j++)
			ans = max(ans,f[n&1][1300][j]);
	cout<<ans<<"\n";
	return 0;
}

标签:ab,int,dfrac,ll,mid,long,ICPC,DEHI,2021
From: https://www.cnblogs.com/nannandbk/p/17632313.html

相关文章

  • [蓝桥杯 2021 省 B] 双向排序 (线段树)
    调了整整5个小时,结果发现自己建树的方式有误,气死我了气死我了,比较好的一道线段树(虽然我不会-----#include<bits/stdc++.h>usingnamespacestd;constintN=1e6+10;intn,m,res,point;vector<int>v[2];//用于存储结果的数组,下标0表示sum为0,下标1表示sum为1structno......
  • CorelCAD中文版下载-CorelCAD 2021(CAD设计工具) 官方版特色
    CorelCAD是一款CAD软件,可以帮助用户设计和绘制2D和3D图形。它提供了许多功能和工具,包括绘图、编辑、注释、测量和布局等。CorelCAD支持多种文件格式,包括DWG、DXF、DWF和PDF等,可以与其他CAD软件进行互操作。此外,CorelCAD还提供了一些高级功能,例如3D建模、渲染、动画和脚本等,可帮助用......
  • 「题解注释」P7518 [省选联考 2021 A/B 卷] 宝石
    联合省选2021宝石题解-hezlik的博客-洛谷博客(luogu.com.cn)耗时:一晚上+半个上午代码注释:#include<bits/stdc++.h>usingnamespacestd;constintN=500000,C=21;intRi(){intx=0,y=1;charc=getchar();for(;c<'0'||c>'9';c=getchar())if......
  • 武家坡2021 可怜你守在寒窑,可怜你孤孤单单。 苦等我薛男平贵,整整一十八年。
    武家坡2021歌词是:三姐,千错万错,乃是为夫一人之错。你你你你你你,你就宽恕了罢。啊~我的妻,王氏宝钏。可怜你守在寒窑,可怜你孤孤单单。苦等我薛男平贵,整整一十八年。啊~我的妻,王氏宝钏。我不该心起疑窦,我不该口吐轻言。落得个忘恩负义,宛如欺了天。待我将这一十八载,从头说一番......
  • Nero2021中文版下载|Nero2021中文版 官方版特色
    Nero10官网版是来自德国的著名的光盘刻录软件,Nero10官网版下载后,可以充分利用以下特性刻录自己的光盘。更快捷地利用遥控功能获取到数码媒体上的文件,整合电视,DVD,图像和声音内容,高级搜索功能,LightScribe支持DVD-R多层和DVD+R双层支持更简便的安装和用户界面。欢迎有需要的小伙......
  • 洛谷 P7739 - [NOI2021] 密码箱
    感觉难度和今年D2T2差不多。首先一个很显然的事情是,每一步得到的分数的分子分母都是互质的,证明参考SBT。而最后答案要求我们将分子分母都求出来而不是求分数值,所以可以很明显的想到将分数当成一个二元组然后维护变换。考虑从右往左扫,假设当前分数为\(\dfrac{x}{y}\),那么扫过......
  • 跑步机出口欧盟BS ISO 20957-6-2021认证如何办理呢?
    BSISO20957-6-2021是一种国际质量标准,用于评估运动器材的安全性和可靠性。如果您的跑步机要出口到欧盟市场,那么获得这个认证是非常重要的,因为它可以向欧盟买家证明您的产品符合欧洲标准和法规。要办理BSISO20957-6-2021认证,您需要按照以下步骤进行:1.了解认证要求:首先,您需要详......
  • 【CV夏季划】2021年有三AI-CV夏季划出炉,冲刺秋招,从CV基础到模型优化彻底掌握...
    2021年的有三AI-CV夏季划正式发布,并且这也是最后一届由言有三本人直接带领的夏季划小组,仅限于今年。有三AI-CV夏季划是言有三直接一对一带领的深度学习和计算机视觉学习计划小组,目标是在新手入门的基础之上,彻底掌握好CV的重要方向,同时提升模型设计与优化的工程代码经验。什么是有三......
  • [SWPUCTF 2021 新生赛]easyupload3.0
    [SWPUCTF2021新生赛]easyupload3.0题目来源:nssctf题目类型:web涉及考点:文件上传easyupload2.0就不写wp了,具体做法跟1.0差不多,不过在bp中把后缀名改成pht上传即可,1.0详见:[SWPUCTF2021新生赛]easyupload1.0如果服务器是Apache的话,配置文件可以添加这些php别名进行解析:php3,p......
  • SolidWorks2021中文版软件图文安装教程,注册激活方法【附安装包下载】
    一、下载方式[软件名称]:SolidWorks2021[软件语言]:简体中文 [软件大小]:14.6G[安装环境]:Win11/Win10[硬件要求]:[email protected]内存@8G及以上下载链接%70%61%6E%2E%62%61%69%64%75%2E%63%6F%6D/%73/%31%47%4B%61%44%46%4D%44%56%77%59%34%75%6E%43%52%74%4C%68%47%36%37%41?%70%77%64=%......