CF1498

A.GCD Sum

CF原题链接

题目大意:

我们用sum1表示n的数位之和,定义gcdSum(x)=gcd(x,sum1)

给出t组数据,每组数据给出n,要求找到最小的整数x,使其满足xngcdSum(x)>1(1t104,1n1018)

解题思路:

第一眼:我丸辣

第二眼:你丸辣

虽然这题看上去不好做,但我们可以想到小学就知道的一件事:若x的数位之和是3的倍数,那么x一定也是3的倍数,对应到这道题中就是此时一定gcdSum(x)3>1

那么也就是说,对于每一个给出的数n,我们最多往上枚举3次就一定能找到答案,敲个暴力嗨皮恩定

可爱的小代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
int T;
int n;

int gcd(int x,int y)
{
	if (y==0) return x;
	return gcd(y,x%y);
}
signed main()
{
	scanf("%lld",&T);
	while (T--)
	{
		scanf("%lld",&n);
		n--;
		int sum,x;
		do
		{
			n++;
			x=n,sum=0;
			while (x)
			{
				sum+=x%10;
				x/=10;
			}
		}while(gcd(n,sum)<=1);
		printf("%lld\n",n);
	}
	return 0;
}

B.Box Fitting

CF原题链接

题目大意:

t 组数据,每组数据给定n个长度为w、高度为1的长方形,给出盒子的长度W(保证w2的幂)。要求求出盒子可放下所有长方形的最小高度,长方形不能重叠、不能立着放。(1t5000,1Σn105,1W109,1w106)

解题思路:

第一眼:丸辣

第二眼:吗

第三眼:真丸辣

显然,我们可以想到每次肯定把长度大的放进去,若放不进去,那必然要多开一行。

于是乎,只需要将wi从大到小排序,再用大根堆维护目前空余的最大值,若当前wi放不进去,那就多开一行,若放得进去,更新一下当前使用的空间就行。

坏代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
int T;
int n,w;
int p[N];
priority_queue <int> q;
int l;

bool cmp(int a,int b) {	return a>b; }
signed main()
{
	scanf("%lld",&T);
	while (T--)
	{
		while (!q.empty()) q.pop();
		q.push(0);
		l=0;
		scanf("%lld%lld",&n,&w);
		for (int i=1;i<=n;i++) scanf("%lld",&p[i]);
		sort(p+1,p+1+n,cmp);
		for (int i=1;i<=n;i++)
		{
			int t=q.top();
			if (t<p[i])
			{
				l++;
				q.push(w-p[i]);
				continue;
			}
			q.pop(); 
			q.push(t-p[i]);
		}
		printf("%lld\n",l);
	}
	return 0;
}

C. Planar Reflections

CF原题链接

题目大意:

t组数据,每组数据给出nk,表示共有n个平面与一个等级为k的粒子。

对与每个能级为k的粒子,当它穿过一个平面时,会向相反方向产生一个能级为k1的粒子,自己方向、能级不变。当一个粒子能级为1时,不会再产生新的粒子。

求能级为k的粒子穿过n个平面后一共有多少个粒子。(t100,Σn,Σk1000)

解题思路:

大概手模一下过程之后容易想到递归。fi,j,k表示对于正在穿第i个平面、能级为j、方向为k的粒子,最后会由它引发出多少粒子。递归式也很好想到,这里就不写了,可以看代码(其实是懒得打字……)

数据量不大,但可以加上记忆化,不然递归会死掉!!

可爱的小代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1010;
const int MOD=1e9+7;
int T;
int n,k;
int f[N][N][2];
//1为右,0为左 
int fd(int num,int lev,int d)
{
	if (f[num][lev][d]) return f[num][lev][d];
	if (lev==1||num==0||num==n+1) return f[num][lev][d]=1;//很明显的边界
	if (d==1) return f[num][lev][d]=(fd(num-1,lev-1,0)+fd(num+1,lev,1))%MOD;//不同方向要分类讨论
	else return f[num][lev][d]=(fd(num-1,lev,0)+fd(num+1,lev-1,1))%MOD;
}
signed main()
{
	scanf("%lld",&T);
	while (T--)
	{
		memset(f,0,sizeof f);//为什么不清空会wa掉呢?因为边界条件不同啦……
		scanf("%lld%lld",&n,&k);
		printf("%lld\n",fd(1,k,1));
	}
	return 0;
}

D.Bananas in a Microwave

CF原题链接

题目大意:

有一个k值,初始化为0;给出n个操作,每个操作给出三个参数t,x,y

对于t=1x0=x/105,可执行不超过y次变换使得k=k+x0

对于t=2x0=x/105,可执行不超过y次变换使得k=k×x0

给出m个询问,对于第i个询问回答k=i最早在哪个操作出现,若无法达到则输出1(n200,m105,x0m)

解题思路:

若不看数据范围,我们duck直接暴力模拟,但暴力复杂度不是说着玩的,于是乎我们想到dp

设状态fi表示k=i最早达到的操作数,gi表示当前操作使得k=i的所需操作数。那么就很好转移了,gk+x0=min(gk+x0,gk+1),对于合法的gifi=cntcnt表示当前的操作数)

不做评价的代码
#incIude <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,m;
int f[N],g[N];
int cnt;

signed main()
{
	memset(f,0x3f,sizeof f);
	scanf("%lld%lld",&n,&m);
	while (n--)
	{
		++cnt;
		int t,x,y;
		scanf("%lld%lld%lld",&t,&x,&y);
		double x0=1.0*x/100000;
		for (int i=1;i<=m;i++)
		{
			if (f[i]!=inf) g[i]=0;//要是已经有答案那就不管了
			else g[i]=inf;
		}
		if (t==1)
		{
			for (int i=0;i<=m;i++)
			{
				int k=ceil(i+x0);
				if (k<=m&&g[i]!=inf) g[k]=min(g[k],g[i]+1);
			}
		}
		else
		{
			for (int i=1;i<=m;i++)
			{
				int k=ceil(1.0*i*1.0*x/100000);
				if (k<=m&&g[i]!=inf) g[k]=min(g[k],g[i]+1);
			}
		}
		for (int i=1;i<=m;i++)
		{
			if (f[i]==inf&&g[i]<=y) f[i]=cnt;//答案转移
		}
	}
	for (int i=1;i<=m;i++)
	{
		if (f[i]==inf) printf("-1 ");
		else printf("%lld ",f[i]);
	}
	return 0;
}

E.Two Houses

CF原题链接
很史的一道交互题,不会不会,咕了咕了


F.Christmas Games

CF原题链接
与“阶梯博弈”有关,不会不会,咕了咕了

posted @   还是沄沄沄  阅读(101)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示