这是水文章(日常笔记)

这里放一些做题目遇到的新东西

怕自己忘记呜呜呜
从2020.11.28开坑呐,初来咋到acm,多多关照~
保证天天更新(做梦) 有想记录的就会加~


2020.11.28

1.01背包问题模板(二维暴力)洛谷找的01模板题

#include<bits/stdc++.h>
using namespace std;


int dp[2000][2000]={0};
int w[2000];
int v[2000];
int t,m;
void bagpack01()
{
	for(int k=1;k<=m;k++)
	{
		for(int c=1;c<=t;c++)
		{
			if(w[k]>c) dp[k][c]=dp[k-1][c];
			else dp[k][c]=max(dp[k-1][c-w[k]]+v[k],dp[k-1][c]);
		}
	}
}

int main()
{	
	cin>>t>>m;
	for(int i=1;i<=m;i++) cin>>w[i]>>v[i];
	bagpack01();
	cout<<dp[m][t]<<endl; 
	return 0;
}

简单解释:关键在公式 dp[k][c]=max(dp[k-1][c-w[k]]+v[k],dp[k-1][c]),也是贪心思想,要判断有可以选择的是否是最大的(最优的)变式训练(真的是变式)

2.结构体排序(二维数组咋用sort?) + cmp和sort
依旧是洛谷发现滴滴滴

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll n,m;
struct cow{      // 二维数组化结构体排序
	ll a,b;
}a[6000];

bool cmp(cow a,cow b)   //cmp从小到大
{
	if(a.a!=b.a) return a.a<b.a;
	else return a.b>b.b;        //直接写成 return a.a<b.a; 就是正宗的cmp
}

int main() {
	ios::sync_with_stdio(0);
	cin>>n>>m;
	for(int i=1;i<=m;i++) cin>>a[i].a>>a[i].b;
	sort(a+1,a+1+m,cmp); //sort
	int i=1;
	ll ans=0;
	while(n)
	{
		if(a[i].b!=0)
		{
			a[i].b--;
			ans+=a[i].a;
			n--;
		}
		else i++;
	}
	cout<<ans<<endl;
	return 0;
}

注意:结构体变量要用sort无论怎么样都要手写cmp 不知道为什么 (我猜是数据类型的问题) ,结构体中间一个成员比较,整个结构体就可以排序。

题解思路第一个女amcer大佬的呜呜呜tql

今天就到这里呜呜呜太菜了洗洗睡吧(下次一定更新


2020.11.29(补题的一天呜呜呜打成残废本来就是废物

1.后缀和最大问题cf的题目
中文翻译:给你一个数组a,满足a1+…+an=0,你每次可以进行以下操作:
选两个数i,j, a[i]=a[i]-1,a[j]=a[j]+1
如果i < j,则操作免费,否则你需要花费1金币。问让全部ai=0,最少需要多少金币
Input
第一行输入一个t(1<=t<=5000),代表t组测试样例.
接下来一行输入一个整数n,代表有n个数(1<=n<=1e5)
再接着输入n个数a1,a2,…,an (-1e9<=ai<=1e9)
Output
输出最少需要花费的金币数量

输入
7
4
-3 5 -3 1
2
1 -1
4
-3 2 -3 4
4
-1 1 1 -1
7
-5 7 -6 -4 17 -13 4
6
-1000000000 -1000000000 -1000000000 1000000000 1000000000 1000000000
1
0
输出
3
0
4
1
8
3000000000
0

#include <bits/stdc++.h>
using namespace std;
 
int main() {
	ios::sync_with_stdio(false), cin.tie(0);
	int t; cin >> t;
	while (t--) {
		int n;
		cin >> n;
		long long cur = 0;
		long long ans=0;
		for (int i = 0; i < n; ++i) {
			long long x; cin >> x;
			cur+=x;
			if(cur<0)
			{
				ans-=cur;
				cur=0;
			}
		}
		cout << ans << endl;
	}
}

利用前缀和做,如果前缀和为负数,就需要用钱来买次数,将负数变成0,用ans记录所需的金币(将整数后面第一个负数先免费抵消,直到所有正数后面都不存在负数,就必须要钱来消掉前面的所有负数),由于数列总和为0,所以只管消除负数,后面会有正数抵消的。当所有遍历完以后,前缀和为0,所有数也为0.
(有一点点模糊,以后多看)

2.
暴力划船

翻译:有n个人想要参加划船比赛。第i个参与者的体重为wi。只有两个人组成的队伍才能参加这次比赛。作为组织者,你认为只允许拥有相同总重量的队伍参赛是公平的。 如果有k团队(a1, b1), (a2, b2),……(ak, bk),每组参赛两人重量相加相等,那么条件a1 + b1 = a2 + b2 =⋯= ak + bk = s, s是每个团队的总重量,那我们就能创建k支队伍。 你的任务是选择这样的团队,人们可以创建的数量是最大可能的。注意,每个参与者只能在一个团队中。

Input
第一行输入一个t1≤t≤1000),代表t组测试样例
接下一行输入一个n(1≤n≤50 ),紧接着输入w1,w2,…,代表第i个人的重量,(1≤wi≤n)
Output
输出一个最大整数k,代表最多有k组参赛人员满足ai+bi=s.
输入
5
5
1 2 3 4 5
8
6 6 6 6 6 6 8 8
8
1 2 2 1 2 1 1 2
3
1 3 3
6
1 1 3 4 2 2
输出
2
3
4
1
2

#include <bits/stdc++.h>
#define ll long long
using namespace std;
 
 ll t;
 ll n;
int main() {
	ios::sync_with_stdio(false), cin.tie(0);
	cin>>t;
	while(t--)
	{
		ll a[2000]={0};
		cin>>n;
		ll x;
		for(int i=1;i<=n;i++)
		{
			cin>>x;
			a[x]++;
		}
		ll sum=0;
		ll ans=0;
		for(int i=2;i<=2*n;i++)
		{
			for(int j=1;j<(i+1)/2;j++)
			{
				if(i-j>n) continue;
				sum+=min(a[j],a[i-j]);
			}
			if(i%2==0) sum+=a[i/2]/2;
			ans=max(ans,sum);
			sum=0;
		}
		cout<<ans<<endl;
	}
}

emmm…样列小的可怕,直接暴力寻找~
先做一个桶存数字的个数,然后在2–2*n之间(也就是1–n之间所有可能的加数和)暴力搜索个数(ex:6=1+5,6=2+4,6=3+3),先在1–(i+1)/2之间找非重复的组合情况(只有偶数存在这种情况),然后假如是偶数,还要格外判断两个数相等(6=3+3),用a[i/2]/2;作为个数,最后比一下要最大的就可以。

今天就到这里,又是怀疑人生的一天呐(cao,氧化钙)


2020.11.30 以前讲过的没明白的点今天来害人了呜呜呜

题目来:链接有特殊要求不挂(校园网)
有一天,有个人问了wgr一个问题,wgr太忙了,所以他把这个问题交给了你,作为
一个小小的考验。有n名编号为1-n的小朋友,他们开始时都没有糖果。接下来q天,
老师每天会打给编号为l-r的小朋友k枚糖果。请输出q天后每位同学的糖果数。

Input
第一行一个整数T(1<=T<=50)表示测试用例的个数
接下来T组数据
对于每组数据,第一行包含两个整数n和q(含义见题目描述,0<n,q<100000)
接下来2-q+1行,每组包含三个整数 l,r,k(含义见题目描述,1<=l<=r<=n,1<=k<=100)

Output
对于每组数据,在一行里依次输出编号1-n的小朋友q天后拥有的糖果数。两个数据之间用空格隔开。
input
1
5 3
2 4 3
1 3 4
1 5 9
output
13 16 16 12 9

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#define ll long long
using namespace std;

ll t;
ll n,q;
ll l,r,k;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>t;
	while(t--)
	{
		ll a[200000]={0};
		cin>>n>>q;
		for(int i=1;i<=q;i++)
		{
			cin>>l>>r>>k;
			a[l]+=k;
			a[r+1]-=k;
		}
		for(int i=1;i<=n;i++)
		{
			a[i]+=a[i-1];
			cout<<a[i]<<" ";
		}
	}
	return 0;
}

解释:题目数据坑死人,暴力做直接超时,有一组阴间数据直接卡你时间,最佳思路用差分做!
差分的定义:将数列中的每一项分别与前一项数做差,第一项前面相当于0,最后一项同理,用另外的数组将差值存起来,前后相加即可得到后一项数值,这样操作避免了暴力从l-r走,时间大大减小为什么我做就想不到呜呜呜 ,由于第一项前面是0,所有差值计算完后,第一项就是所求的数,(前面也是加0嘛),然后用这个一直往后加上差值,找到所有数的值完毕。

由于上课就写这些呜呜呜


2020.12.3摸了几天鱼又来更新了呜呜呜

来一个stl的二分函数lower_bound,upper_bound这两玩意确实好用

上题目:众所周知,yhm是我们ACM的组花,大家都很喜欢她,所以对yhm的生日额外关心。这天,yjj跟yhm聊天的时候,就提起了生日,yhm问yjj她的生日是什么时候,yjj’顿时就慌了,因为yjj居然忘记了yhm的生日。yhm很生气,事情很严重,但是善良的yhm还是给了yjj一个机会:给定两个无序的数组a[]和b[],在给定两个数字n和m,现在要求你现将数组从小到大排好序,然后从a数组找到第一个不小于n的位置k1(如果没有,k1=N);从b数组找到第一个不小于m的位置k2(如果没有,k2=N)。然后将k1对12取模(特别注意不会出现0月)代表生日的月份;将k2对(30或31取模,不考虑平闰年,为了题目方便,2月有30天)代表生日是几号。然后按k1-k2格式输出yhm的生日。现在yjj把问题交给你,如果你不能在1s内回答出来,yhm将会罚yjj跪CPU。请你救救可怜的yjj吧!

Input
第一行一个整数T,代表T组数据。
第二行两个整数 N,Q,N代表a,b数组的大小(a,b一样大),询问Q次。
第三行输入a数组。
第四行输入b数组。
以下Q行输入两个整数n,m(跟题目描述的含义)。

Output
输出Q行,每行按格式k1-k2输出。

input
1
10 3
9 8 7 6 5 4 3 2 1 0
1 3 5 7 9 11 13 4 4 8
2 2
5 6
7 5
output
03-02
06-06
08-05

tle:2s

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#define ll long long
using namespace std;
int check(ll a)
{
	if(a==1||a==3||a==5||a==7||a==8||a==10||a==12) return 1;
	else return 0;
}
ll t;
ll N,q;
ll a[200000],b[2000000]; 
ll n,m;
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin>>t;
	while(t--)
	{
		cin>>N>>q;
		for(int i=1;i<=N;i++) cin>>a[i];
		for(int i=1;i<=N;i++) cin>>b[i];
		sort(a+1,a+1+N); sort(b+1,b+1+N);
		while(q--)
		{
			cin>>n>>m;
			ll x=0,y=0;
			if(a[N]<n) x=N;
			else
			x=lower_bound(a+1,a+1+N,n)-(a);
			if(b[N]<m) y=N;
			else
			y=lower_bound(b+1,b+1+N,m)-(b);
			x%=12;
			if(x==0) x=12;
			if(check(x)) 
			{
				y%=31;
				if(y==0) y=31;
			}
			else
			{
				y%=30;
				if(y==0) y=30;
			 }
			printf("%02lld-%02lld\n",x,y);
		}
	}
	return 0;
}

题目里面关键是找在一个有序序列里面找一个最先一个不小于某个常数的下标,这种自然可以用二分,速度快而且稳定,题目数据卡的死,暴力不可能过,二分对于有序的长度大小很大的数组有好的查找性。

补充:upper_bound函数有三个参数,首地址,尾地址和需要比较的数K(好像还有第四个参数,下次一定 )(upper_bound同理),lower_bound是找第一个不小于>=K的地址,而upper_bound是第一个大于K的地址,两组略有不一样,而且注意,函数返回值是地址,所以需要减掉第一个数的地址,来获得相对位置,也就是该数的下标(见答案)。

嗯,还是来补充神奇的第四个参数呜呜呜 。和sort类似(前面有噢),第四个参数可以写一个cmp函数来将递减数列变成递增数列来同样实现

手写个p ,查资料发现一个巨好用的东西greater()和less();
它们相当于cmp函数的作用 并没有深究 如果是递减数列要用lower upper,可以加在后面加第四个参数greater(),这样就可以找到相同的数,只是位置有点变化(即变成了大于变成了第一个小于(等于)的)
上比较代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector> 
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;

//递减数列
int main()
{
	ios::sync_with_stdio(0); cin.tie(0);
	int a[5]={5,4,3,2,1};
	int x=upper_bound(a,a+5,2,greater<int>())-a;
	cout<<x<<endl;  //x输出为4,即2那个数
	return 0;
}

//递增数列
int main()
{
	ios::sync_with_stdio(0); cin.tie(0);
	int a[5]={1,2,3,4,5};
	int x=upper_bound(a,a+5,2)-a;
	cout<<x<<endl;   //x输出2,即2那个数
	return 0;
}

PS:
同理在sort函数里面都可以用!
sort(a,a+n,greater()),既可以实现从大到小排序噢~,换成less()就是从小到大,不加也可以,默认是从小到大。

麻麻再也不用担心我不会手写cmp啦
今天就到这里,6号新生赛啦,加油加油!!!


2020.12.08回来啦

新生赛也终于落下了帷幕,虽然打非常弱智,但是还是侥幸进了想进的acm组呀呜呜呜感动,补一下新生赛的几个卡的弱智数学题目,被自己蠢到了,以后要学新算法啦,准备开新坑 下次一定呜呜呜

第一题:阳光灿烂的这一天里,佩奇和苏西又一如既往在玩着游戏,恍惚间,苏西和佩奇又想起了2018的那个难忘的暑假,所以他们打算玩一个关于8的游戏。 苏西一眼看出2018并不是8的倍数,佩奇说2016是8的倍数啊,但苏西和佩奇并不知道2020是不是8的倍数,希望你能迅速告诉他们,一个数是不是8的倍数。

Input
输入正整数t,表示接下来t组数据 t<=100000 输入一个正整数n,表示要求的数字 n(n =e2000) 就是两千次幂

Output
如果n是8的倍数,输出"yes" 否则输出"no"

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
ll t;
char a[30000];
int main() {
	cin>>t;
	while(t--) {
		cin>>a;
		int x=strlen(a);
		ll b=0;
		if(x==1) {
			b=a[0]-'0';
			if(b%8==0) cout<<"yes"<<endl;
			else cout<<"no"<<endl;
		}
		if(x==2) {
			b=(a[1]-'0')+(a[0]-'0')*10;
			if(b%8==0) cout<<"yes"<<endl;
			else cout<<"no"<<endl;
		}
		if(x>=3) {
			b=(a[x-1]-'0')+(a[x-2]-'0')*10+(a[x-3]-'0')*100;
			if(b%8==0) cout<<"yes"<<endl;
			else cout<<"no"<<endl;
		}

	}
	return 0;
}

这个数据范围有点阴间,是大数的8倍数判断当时忘记了8的倍数咋判断,一时半会我也推不出规律呜呜呜 ,然后一直卡,看着别人a的快乐,我在罚坐,现在总结一下一些常用的倍数判断: (符号意思与上面代码一致)

2的倍数:这个。。。其实就是奇偶的判断,可以用位运算来最后一位a[x-1] (x为字符串长度,也就是位数)if(a[x-1]&1) cout<<"no"<<endl; else cout<<"yes"<<endl;

3的倍数:3的倍数特征是一个数的各位数之和是3的倍数,这个数就是3的倍数(来自度娘orz)代码就这么写:

for(int i=x-1;i>=0;i--)
{
   b+=(a[i]-'0');
}
if(b%3==0) cout<<"yes"<<endl;
else cout<<"no"<<endl;

4的倍数:末尾两位是4的倍数。因为100或100的倍数必然是4的倍数,只要末尾两位也是4的倍数即可。(与8的倍数同理)

8的倍数:末三位是8的倍数,必然的8的倍数,152*8=1000(代码在题解里面)

5的倍数:末尾数字为5或0的数if(a[x-1]=='5'||a[x-1]=='0') cout<<"yes"<<endl; else cout<<"no"<<endl;

6的倍数:只要一个数能被2,3同时整除,也就是同时是2,3的倍数,就为6的倍数(两种放在一起验证,两者都符号就yes)

7的倍数有点复杂

若一个整数的个位数字截去,再从余下的数中,减去个位数的2倍,如果差是7的倍数,则原数能被7整除。

例如:133,判断133是否7的倍数的过程如下:13-3×2=7,所以133是7的倍数;

如果差太大或心算不易看出是否7的倍数,就需要继续上述「截尾、倍大、相减、验差」的过程,直到能清楚判断为止。

例如,又例如判断6139是否7的倍数的过程如下:613-9×2=595 , 59-5×2=49,所以6139是7的倍数。 (这好像对大数有点难实现)

9的倍数:9的倍数的特征是:整数各个位数字和是9的倍数。(实现同3的倍数)

其他的补充:

11的倍数特征:

1、整数末三位与前几位的差是11的倍数。

2、整数奇数位数字之和与偶数位数字之和的差是11的倍数。

13的倍数特征:

整数末三位与前几位的差是13的倍数。

25的倍数特征:

整数末两位是25的倍数。

125的倍数特征:

整数末三位是125的倍数。

第二题同样是脑瘫的数学题目
求正n多边形的面积,规定π=3.141592653589793

Input
输入正整数t,表示接下来t组数据 输入一个正整数n,一个正整数d,表示多边形的边长 保证3<=n,d<=1000,d<=1000

Output
输出正n多边形的面积,答案只保留整数。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;

double pi=3.141592653589793,a,b,s;
int t,d,n;
int main() {
	cin>>t;
	while(t--)
	{
		cin>>n>>d;
		a=pi/n;
		b=tan(a);
		s=d*d*n/b/4;
		printf("%.0lf\n",s);
	}
	return 0;
}

公式: 假设正 n 边形的边长为 a 的话 S n边形 = (aan/4) · [ ctg (180/n) ]

还有一种:正n边形的面积公式为s=0.5sin(2π/n)nr2,当n趋近于无穷时,sin(2π/n)=2π/n(这是高数里面的等价无穷小),那么得到的就是圆的面积s=πr2

推导过程:正n边形的所有顶点都在同一个外接圆上,将正n边型的顶点都与外接圆的圆心相连将正n边型分成n个全等等腰的三角形,等腰三角形的顶角为2π/n,可求得小等腰三角形的面积为0.5sin(2π/n)r^2,再乘以等腰三角形的个数n即得。
r的求法也在这个小的等腰三角形中求,假设正n边型的边长为l,则0.5l/r=sin(π/n),r=l/2sin(π/n)
度娘万岁
今天就到这里啦~


2020.12.16 熬夜div3刷题补题

#690 div3 D 水题不会做 原题链接
老规格上代码

#include<bits/stdc++.h>
#define int ll
#define ll long long
#define fp for(int i=1;i<=n;i++)
const ll N = 2e6;
using namespace std;

 ll t;
 ll n;
 ll a[N];
 int gets(ll q)
{
	ll p=0;
	fp
	{
		p+=a[i];
		if(p>q) return 0;
		if(p==q) p=0;
	}
	return 1;
}
 void solve()
 {
 	scanf("%d",&n);
 	ll sum=0;
 	fp
 	{
 		scanf("%d",&a[i]);
 		sum+=a[i];
	 }
 	for(int i=1;i<=sum;i++)
 	{
 		if(sum%i!=0) continue;
 		if(sum%i==0&&gets(i))
 		{
 			cout<<n-sum/i<<endl;
 			break;
		 }
	 }
 }

signed main() {
	ios::sync_with_stdio(0), cin.tie(0);
	scanf("%d",&t);
	while(t--) solve();
	return 0;
}

思路: 关键在于,数字相等时的结果为sum(sum为数列的和)的因子(因为每个数大小没有发生改变,故如果数合成都相等的大小时,那么相等的数一定是sum的因子,我们逆向思考,如果把和为sum的数列分成相等数的排列形式 eg. sum=9,我们可以分成9个1,3个3,1个9即为sum的因子

然后就是去枚举sum的因子,然后再去一个个累加验证,gets函数里面由于的相邻的数去组合,故从1-n去累加枚举前缀和,如果前缀和等于因子,则表示满足一组,前缀和清0,继续枚举下一数,如果大于因子则该因子一定不是答案,之间跳出。如果每一组前缀和都为因子,则该因子就是答案,只要n-sum/i就是答案。

摸了好久的鱼呜呜呜 水题也做不出了

2020.12.17丑数问题优化加滑动窗口

摸鱼的一天开始了

1.滑动窗口问题
给定一个大小为n≤106的数组。
有一个大小为k的滑动窗口,它从数组的最左边移动到最右边。
您只能在窗口中看到k个数字。
每次滑动窗口向右移动一个位置。

k=3时

窗口位置
[1 3 -1] -3 5 3 6 7
1 [3 -1 -3] 5 3 6 7
1 3 [-1 -3 5] 3 6 7
1 3 -1 [-3 5 3] 6 7
1 3 -1 -3 [5 3 6] 7
1 3 -1 -3 5 [3 6 7]

输入样例:
8 3
1 3 -1 -3 5 3 6 7
输出样例:
-1 -3 -3 -3 3 3
3 3 5 5 6 7

#include<bits/stdc++.h>
#define int ll
#define ll long long
#define fp for(int i=1;i<=n;i++)
const ll N = 2e6;
using namespace std;

 ll n,k;
 ll a[N],q[N],hh,tt;


signed main() {
	ios::sync_with_stdio(0), cin.tie(0);
	scanf("%lld%lld",&n,&k);
	fp scanf("%lld",&a[i]);
	
	hh=0,tt=-1;
	fp
	{
		if(hh<=tt&&i-k>=q[hh]) hh++;   //判断队头是否已经滑出窗口
		while(hh<=tt&&a[q[tt]]>=a[i]) tt--;  
		//若加入进来的数小于等于队尾的数,直接删除队尾来维护单调性,
		//因为此时队尾的数已经不可能被输出了,去除优化时间
		q[++tt]=i;   //队列里面存下标,方便判断和移动,这里是入队
		if(i>=k) printf("%d ",a[q[hh]]);  //最小值
	}
	printf("\n");
	
	//下面输出最大值是镜像对称的,只需要改变判断的条件
	hh=0,tt=-1;
	fp
	{
		if(hh<=tt&&i-k>=q[hh]) hh++;
		while(hh<=tt&&a[q[tt]]<=a[i]) tt--;
		q[++tt] =i;
		if(i>=k) printf("%d ",a[q[hh]]);   //最大值
	}
	return 0;
}

这个题目是单调队列优化的经典板子题(正常模拟做O(n*n))暴力出奇迹 我们要用模拟队列来维护其中值的单调性,实现单调队列,然后只要对头出队的第一个元素就要找的元素。

用数组模拟队列,tt为队尾,hh为队首,在队尾进数,并判断维持单调性,在对头出队输出最值优化成了几乎O(n)的复杂度 数据结构算法yyds

2.丑数优化
丑数是指不能被2,3,5以外的其他素数整除的数。把丑数从小到大排列起来,结果如下:
1,2,3,4,5,6,8,9,10,12,15……
求第1500个丑数
水题 没有输入(虽然输出很阴间)

#include<bits/stdc++.h>
#define int ll
#define ll long long
#define fp for(int i=1;i<=n;i++)
const ll N = 2e6;
using namespace std;

ll ugly_number(ll n)
{
	if(n==1) return 1;
	queue<ll> a,b,c;
	a.push(2),b.push(3),c.push(5);
	ll ans=0;
	while(n-->1)
	{
		ans=min(min(a.front(),b.front()),c.front());
		if(ans==a.front())
		{
			a.pop();
			a.push(ans*2);
			b.push(ans*3);
			c.push(ans*5);			
		}
		else if(ans==b.front())
		{
			b.pop();
			b.push(ans*3);
			c.push(ans*5);			
		}
		else if(ans==c.front())
		{
			c.pop();
			c.push(ans*5);			
		}
	}
	return ans;
}


signed main() {
	ios::sync_with_stdio(0), cin.tie(0);
	ll ans=ugly_number(1500);
	printf("The 1500'th ugly number is %lld.\n",ans);
	return 0;
}

稍微分析一下,既然是除2,3,5以外的素数,那么只要是因子只为2.3.5三种的数就是丑数 我看着也挺漂亮的呀 就是枚举起来有点费时间…
那我们来优化,我们要求第1500个丑数,我们可以自己来构造丑数呀这样从1-1500时间大大减少,就从2.3.5三个数开始,分成三组比如第一组:2,22,42,82…第二组:3,23,3*3
关键就在如果实现顺序输出,我们可以用三个队列来维护输出顺序,在队尾将大的入队,将丑数都分类入队,在让ans在三个队的队头取最小值,依次取数即可 思路妙但是自己写不出呜呜呜

参考链接
大佬的博客

肉眼可见的恐怖优化orz

今天就到这里~


2020.12.18教育场补题

B题链接

#include<bits/stdc++.h>
#define ll long long
#define fp for(int i=1;i<=n;i++)
const ll N = 2e6;
using namespace std;
 
ll t;
ll n;
ll a[N];
 
void solve()
{
	cin>>n;
	fp cin>>a[i];
	fp
	{
		ll x=1;
		while(x*2<=a[i]) x*=2;
		cout<<x<<" ";
	}
	cout<<endl;
}
int main() {
	ios::sync_with_stdio(0), cin.tie(0);
	cin>>t;
	while(t--) solve(); 
	return 0;
}
 
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这次一定ac

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值