算法刷题记录

这篇具有很好参考价值的文章主要介绍了算法刷题记录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

cf题目记录
773

A题

给定三个坐标

就是让你求两个y相同时x的差,这个y要是最大的y

#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
using namespace std;
struct nott{
	int x;
	int y;
}n[100000];
bool cmp(nott x1,nott x2){
	if(x2.y!=x1.y) return x1.y<x2.y;
	return x1.x<x2.x;
}
int main(void) {
int t;
cin>>t;
while(t--){
	for(int i=1;i<=3;++i){
		cin>>n[i].x>>n[i].y;
	}
	int ans=0;
	sort(n+1,n+4,cmp);
//	for(int i=1;i<=3;++i) cout<<n[i].x<<" "<<n[i].y<<" ";
//	cout<<"\n";
	for(int i=1;i<=2;++i){
		if(n[i].y==n[i+1].y){
			if(i==2) ans=n[3].x-n[2].x;
		}
	}
cout<<ans<<"\n";
}
return 0;
}
//		if(y[1]==y[2]&&y[1]!=0&&y[3]<y[1]) ans=abs(x[1]-x[2]);
//		else if(y[1]==y[3]&&y[1]!=0&&y[2]<y[1]) ans=abs(x[1]-x[3]);
//		else if(y[2]==y[3]&&y[2]!=0&&y[1]<y[2]) ans=abs(x[2]-x[3]);
//		cout<<ans<<endl;

收获:ans我本来定义的是double,因为我看题目输出是浮点数,然后wa了,发现大数相减时,会把后面的省略了,比如

//698826176 540020274
//890345633 540020274
//他输出191519000.0000000000
//而答案应该是191519457.0000000000

然后把double改为int就行了,因为减数和被减数都是int型的

772

B

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=2e5+10;
int a[N],ans[N];
int main(void) {
int t,n;
cin>>t;
while(t--){
	cin>>n;
	fill(ans,ans+n+1,0);
	int k=0,sum=0;
	for(int i=1;i<=n;++i) cin>>a[i];
	for(int i=2;i<=n-1;++i){
		if(a[i]>a[i-1]&&a[i]>a[i+1]) {
			ans[++k]=i;
			sum++;
		}
	}
	for(int i=1;i<=k;++i){
		if(i==k) a[ans[k]]=max(a[ans[k]-1],a[ans[k]+1]);
		if(ans[i+1]-ans[i]==2) {
			a[ans[i]+1]=max(a[ans[i]],a[ans[i+1]]);
			sum--;
			i++;
		}
		else a[ans[i]]=max(a[ans[i]-1],a[ans[i]+1]);
		
	}
	cout<<sum<<endl;
	for(int i=1;i<=n;++i) cout<<a[i]<<" ";
	cout<<endl;
} 
return 0;
}


A题

题意 如果两个数字或运算与原数或运算相当,则可以用这两个数代替原来的数,问经过一系列操作后,数字总和最小是多少

思路:把所有数或运算一遍即可得到答案,因为如果是1,肯定不能通过操作改变这个1,只有两个都是1才能通过操作把其中一个1变为0使得结果保持不变

#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=2e5+10;
int a[N];
int main(void) {
int t,n;
cin>>t;
while(t--){
	cin>>n;
	int ans=0;
	for(int i=1;i<=n;++i) {
		cin>>a[i];
		ans=ans|a[i];
	}
	cout<<ans<<endl;
}
return 0;
}

122 B题

01串的问题,哪个个数少删掉哪个,求能删掉的最大个数

思路:如果字符串中0和1的数量不相等,删掉最少的个数,如果相等 则只能删掉原有的个数减1

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
const int N=2e5+10;
char str[N]; 
int main(void) {
int n;
cin>>n;
while(n--){
	cin>>str;
	int sum1=0,sum2=0;
	int len=strlen(str);
	for(int i=0;i<len;++i){
		if(str[i]=='0') sum1++;
		else sum2++;
	}
	if(sum1==sum2) cout<<sum1-1<<endl;
	else cout<<min(sum1,sum2)<<endl;
}
return 0;
}

126

B

就是给你一个数字,两个操作,

n=(n+1)%32768或n=(n*2)%32768

问变到0所需的最小操作数

#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
queue<int>q;
const int mod = 32768;
const int N = 2e5 + 10;
int dis[N],ch[N];
void bfs() {
	int u;
	while (!q.empty()) q.pop();
	memset(dis, 0, sizeof(dis));
	q.push(mod);
	dis[mod] = 1;
	dis[0] = 1;
	while (!q.empty()) {
		 u = q.front();
		 //cout << u << " ";
		q.pop();
		if (!dis[u - 1]) {
			dis[u - 1] = dis[u] + 1;
			q.push(u - 1);
		}
		if ((!dis[u / 2]) && (u % 2 == 0)) {
			dis[u / 2] = dis[u] + 1;
			q.push(u / 2);
		}
		if ((!dis[(u + mod)/2]) && ((u + mod) % 2 == 0)) {
			dis[(u + mod)/2] = dis[u] + 1;
			q.push((u + mod)/2);
		}
	}
}
int main(void) {
	
	int n;
	cin >> n;
	bfs();
	for (int i = 1; i <= n; ++i) {
		cin >> ch[i];
	}
	for (int i = 1; i <= n; ++i) {
		cout << dis[ch[i]] - 1 << " ";
	}
	return 0;
}

这种做法是把32768先放到队列中,然后倒推

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <map>
#include <cstring>
#include <queue>
using namespace std;
queue<int>q;
const int mod = 32768;
const int N = 1e6 + 10;
int dis[N];
int ch[N];
int main(void) {
	int a, x;
	cin >> x;
	for (int i = 1; i <= x; ++i) {
		cin >> a;
		while (!q.empty()) q.pop();
		memset(dis, 0x3f, sizeof(dis));
		dis[a] = 0;
		q.push(a);
		while (!q.empty()) {
			int u = q.front();
			q.pop(); 
			if ((u + 1) == mod) {
				dis[u + 1] = dis[u] + 1;
				break;
			}
			 if (u*2  == mod ) {
				 dis[u * 2] = dis[u] + 1;
				break;
			}
			if ( dis[(u+1)%mod] == 0x3f3f3f3f) {
				dis[(u+1)%mod] = dis[u] + 1;
				q.push((u+1)%mod);
			}
			if ( dis[(u*2)%mod] == 0x3f3f3f3f) {
				dis[(u *2)%mod ] = dis[u] + 1;
				q.push((u*2)%mod);
			}
		}
		cout << dis[32768]<<" ";
	}
		return 0;
}

这是正着写的做法,但是TLE,因为很多组数据嘛,而我是每输入一个进行一个操作,显然没有刚才把所有的答案先初始化好来的快

大二题目记录

day1A题

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int n,m,c1,c2,v,t;
const int N=1e5+10;
const int inf=0x3f3f3f3f;
int stair[N],ele[N];
void solve(){
	int x1,x2,y1,y2;
	int sum;
	cin>>n>>m>>c1>>c2>>v;
	for(int i=1;i<=c1;++i) cin>>stair[i];
	for(int i=1;i<=c2;++i) cin>>ele[i];
	sort(stair+1,stair+c1+1);//上面的输入下标决定是否要加1 
	sort(ele+1,ele+c2+1);
	cin>>t;
	while(t--){
	int ans=inf;
	int b,d;
		cin>>x1>>y1>>x2>>y2;
		if(x1==x2) cout<<abs(y1-y2)<<endl;
		else{
		if(stair[1]!=0){
			int a=lower_bound(stair+1,stair+c1+1,y1)-stair;//这里要减去首地址 
		if(a>1) {
			b=a-1;
			sum=abs(stair[b]-y1)+abs(x2-x1)+abs(stair[b]-y2);
		ans=min(ans,sum);
		}
		sum=abs(stair[a]-y1)+abs(x2-x1)+abs(stair[a]-y2);
		ans=min(ans,sum);
		} 
		if(ele[1]!=0){
		int c=lower_bound(ele+1,ele+c2+1,y1)-ele;
		if(c>1){
		d=c-1;	
		sum=abs(ele[d]-y1)+ceil(1.0*abs(x2-x1)/v)+abs(ele[d]-y2);
		ans=min(ans,sum);
		}
		sum=abs(ele[c]-y1)+ceil(1.0*abs(x2-x1)/v)+abs(ele[c]-y2);
		ans=min(ans,sum);
		}
	cout<<ans<<endl;	
		}
	}
} 
int main(void) {
solve();
return 0;
}

收获:1:sort排序和二分查找这两个知识点,而且括号里的参数容易错,二分返回的是地址,如果要是下标记得减去数组

​ 2:刚开始用暴力遍历,显然TLE,然后就要想到最近的肯定就是只有那四种可能,然后比较那四种可能就行了

​ 3:特殊情况没考虑到:比如说在同一层时,需要特判,比如没有电梯或楼梯时

训练赛题目
第一次天梯赛

7-12 哲哲打游戏

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1e5+10;
vector<int>ch[N];
int ans[N];
int main(void) {
int t,n,m,now=1;
int x,y,h;
cin>>n>>m;
for(int i=1;i<=n;++i){
	cin>>t;
	for(int j=1;j<=t;++j){
	//cin>>ch[i][j];
	cin>>h;
	ch[i].push_back(h);//怎么存进去
	}
}
int i=1;
while(m--){
	cin>>x>>y;
	if(x==0) now=ch[now][y-1];//这里是y-1
	else if(x==1) {
		cout<<now<<endl;
		ans[y]=now;
	}
	else if(x==2) now=ans[y];
}
cout<<now;
return 0;
}

my reward:

1.首先我开二维数组,爆了,所以这时要用vector来搞数组,csdn说一般二维数组每一维不超过1e4

2.vector的用法,存数据用push_back,在找数组元素的时候,注意他的第二维是从0开始的,所以上面的代码是y-1

刚开始我就写成了y,然后读数据的时候就直接读到一半就卡在那里了

7-10 病毒溯源

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N=1e4+10;
int book[N],a[N],b[N];
vector<int>g[N];
int maxx=-1;
void dfs(int x,int step){
	int len=g[x].size();
	if(len==0){
		if(step>maxx){
		maxx=step;
		for(int i=0;i<step;++i)
		b[i]=a[i];	//输出路径?为什么要再设个b数组
		}
		return ;
	}
	for(int i=0;i<len;++i){
		a[step]=g[x][i];//用于记录路径的
		dfs(a[step],step+1);
	}
}
int main(void) {
int n,t,x,j;
cin>>n;
for(int i=0;i<n;++i){
	cin>>t;
	for(int k=1;k<=t;++k){
		cin>>x;
		book[x]=1;//和拓扑排序那个入度差不多,肯定要找入度为0的作为起始点
		g[i].push_back(x);
	}
	sort(g[i].begin(),g[i].end());//啊啊啊啊 因为优先筛选小的序列
}
for(int i=0;i<n;++i){
	if(book[i]==0) {
		j=i;
		break;
	}
}
a[0]=j;//
dfs(j,1);
cout<<maxx<<endl;
for(int i=0;i<maxx;++i){
	if(i==maxx-1) cout<<b[i];
	else cout<<b[i]<<" "; 
}
return 0;
}

my reward

1.那个sort的那个排序,为了确保优先筛选小的序列,很巧妙欸,而且也不知道vector也能这样排序的,用begin和end

2.dfs记录路径的问题,

7-6 吉老师的回归

#include <bits/stdc++.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring> 
using namespace std;
const int N=1e4+10;
int main(void) {
	ios::sync_with_stdio(false);
	cin.tie(0); 
int n,t,sum=0,flag=1;
string s;
string s1="qiandao",s2="easy";
cin>>n>>t;
	getline(cin,s);
	//getchar();这里用这个就不行,真奇怪 
for(int i=1;i<=n;++i){
	getline(cin,s);
	if(s.find(s1)!=s.npos) continue;//上下两行是等价的,看下面的reward,找不到有两种返回值???
	if(s.find("easy")!=-1) continue;
	if(sum==t) {
	cout<<s;	
	flag=0;
	sum++;
	}
	else sum++;
}
if(flag) cout<<"Wo AK le";
return 0;
}

my reward:

1.查找字符串怎么找,

find函数,如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回string::npos,

find()函数的用法,会找到匹配的字符串,找到返回第一次出现的首地址,找不到则返回-1

函数里面可以是具体的字符值,也可以是变量。我比赛时写的是循环遍历一个一个字母找,真的弱智,

2.关闭同步流的操作,那两行缺一不可,否则输出的答案就不会在最后面了

3.为什么getchar不行,必须要用getline呢,数字与字母之间

7-11 清点代码库

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
map<vector<int>, int>mp;
const int N = 1e5 + 10;
int ch[N];
int main(void) {
	int n, m;
	int x;
	cin >> n >> m;
	mp.clear();
	vector<int>v(m);
	for (int i = 1; i <= n; ++i) {
		v.clear();
		for (int j = 1; j <= m; ++j) {
			cin >> x;
			v.push_back(x);
		}
		mp[v]++;
	}
	cout << mp.size() << "\n";
    //从大到小找,找mp的第二维,有的话就输出,然后两个测试点超时了
	for (int i = n; i >= 1; --i) {
        //是这层循环太复杂了,因为每次找mp的第二维都要从头开始找,所以要怎么办呢
        //然后就要想到用vector来存取mp里的值,每次找mp的第二维的时候,可以直接通过下标来访问,就不用循环啦
		for (auto t : mp) {
			if (t.second == i) {
				cout << i;
				for (auto x : t.first) {
					cout << " " << x;
				}
					cout << "\n";
			}
		}
	}
	return 0;
}

//#include <stdio.h>
//#include <iostream>
//#include <vector>
//#include <map> 
//#include <algorithm>
//using namespace std;
//const int N=1e4+10;
//map<vector<int>,int>mp;
//vector<vector<int> >v[N];
//int main(void) {
//int n,m;
//int ans=0;
// cin>>n>>m;
// for(int j=1;j<=n;++j){
// 	vector<int>g(m);
// 	for(int i=0;i<m;++i){//这里要从0开始哦 
// 		cin>>g[i];
//	 }
//	 mp[g]++;
// }
// for(auto t:mp){
// 	v[t.second].push_back(t.first); 
// 	ans++;
// }
// cout<<ans<<endl;
// for(int i=n;i>=1;--i){
// 	for(auto t:v[i]){
// 		cout<<i;
// 		for(auto a:t) { //敲重点哦,输出数组元素还要再开个循环
// 			cout<<" "<<a;
//		 }
// 		cout<<endl;
//	 }
// }
//return 0;
//}当我map存了数组和对应的个数时,想要输出,却没有什么好办法
怎么想到用vector的


#include <bits/stdc++.h>
using namespace std;
map<vector<int>,int>mp;
const int N=1e4+10;
//vector<int,vector<int> >vxx;
vector<vector<int> >vxx[N];//为什么要V[N]呢 不能是V 因为下面 vxx[t.second].push_back(t.first)

int main(void){
	int n,m,ans=0;
	cin>>n>>m;
	for(int j=1;j<=n;++j){
	vector<int>v(m);//这个一定要写这里,放最上面就寄了,因为每次循环不可能把vector原有的删了 
		for(int i=0;i<m;++i){
			cin>>v[i];//经过实验发现,如果这里写的是cin>>x;  v[i].push_back(x) 在数组的前面会多出三个0,因为样例给的m是3,然后vector开辟三个数组,并且都初始化为0,所以push_back就会在他之后加上元素。解决办法就是每次clear一下就行啦
		}
		mp[v]++;
	}
	for(auto t: mp){
		vxx[t.second].push_back(t.first);//个数作为下标,便于下面循环,你看下面循环的i值是从大到小的
		ans++;
	}
	cout<<ans<<endl;
	for(int i=n;i>=1;--i){
		for(auto t:vxx[i]){//如果没有元素的话,就不会循环,所以不需要用if来判断 
			cout<<i;
				for(auto x:t) {
					cout<<" "<<x;
				}
				cout<<endl;
		}
	}
	return 0;
} 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QXSizD6E-1690427959413)(C:\Users\14716\AppData\Roaming\Typora\typora-user-images\image-20220409113150190.png)]

第二次天梯赛

7-13 那就别担心了

#include <bits/stdc++.h> 
using namespace std;
vector<int>v[510];
int way[510];
int flag=1;
int dfs(int s){
	if(way[s]>0) return way[s];
	if(v[s].size()==0) flag=0;
    //这样写也是对的
//	for(int i=0;i<v[s].size();++i){
//		way[s]+=dfs(v[s][i]);
//	}
    //atuo错误教学
//for(auto t: v[s]){
//	way[s]+=dfs(v[s][t]);
//}    
for(auto t: v[s]){
	way[s]+=dfs(t);//这里容易错
} 
	return way[s];
}
int main(void) {
int n,m,x,y,start,fina;
cin>>n>>m;
while(m--){
	cin>>x>>y;
	v[x].push_back(y); 
}
cin>>start>>fina;
way[fina]=1;
cout<<dfs(start)<<" ";
if(flag) cout<<"Yes";
else cout<<"No";
return 0;
}

think:dfs加记忆化搜索,把终点值记为1,假如到头了却没经过终点,flag=0

第三次天梯赛

7-11 深入虎穴

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N=1e5+10;
vector<int>g[N];
char str[101];
int ru[N];
int maxx=0,ans=0;
void dfs(int s,int step){
	if(g[s].size()==0) {
	if(step>maxx) {
	maxx=step;	
	ans=s;
    	}
    	return;//return 有没有貌似影响不大  
	}
	for(int i=0;i<g[s].size();++i){//敲重点,是00000000
		dfs(g[s][i],step+1);
	}
}
int main(void) {
int n,t,x;
cin>>n;
for(int i=1;i<=n;++i){
	cin>>t;
	while(t--){
		cin>>x;
		g[i].push_back(x);
		ru[x]++;
	}
}
for(int i=1;i<=n;++i){
	if(ru[i]==0){
		dfs(i,1);//如果写成0有个样例过不了 
		break;
	}
}
cout<<ans;
return 0;
}

think:比赛时没有想到入度,直接dfs(1,0)去了,还有一个地方是在循环遍历的时候,写成1了,敲重点!!!!

如果写成1了,就不可能对

#include <bits/stdc++.h>
#include <cstring>
using namespace std;
int main(void){
	string str;
	int j;
	getline(cin,str);//读取一整行
	//int len=str.size();
//	int len=str.length();
	for(int i=0;i<str.size();++i){///1111
		if(str[i]=='6'){
			for( j=i+1;j<str.size()&&str[j]=='6';j++);//222222
			if(j-i>3&&j-i<=9) str.replace(i,j-i,"9");
			else if(j-i>9) str.replace(i,j-i,"27");
//	for( j=1;i+j<str.size()&&str[i+j]=='6';++j);
//	if(j>9) str.replace(i,j,"27");
//	else if(j>3) str.replace(i,j,"9");
		}
	}
	cout<<str<<endl;
	return 0;
}

reward:字符串操作replace的用法,还有整行读取的使用,pta不支持gets,比赛时用gets编译都过不了

还有一个问题就是,定义一个len放在循环判断里面不太行,单独放在1或者2没问题,同时放上去就不行,不知道为什么

第四次天梯赛

7-11 名人堂与代金券

#include <bits/stdc++.h>
#include <stack>
#include <cstring>
using namespace std;
struct people{
	char name[50];
	int num;
}p[10002];
bool cmp(struct people x,struct people y){
	if(x.num==y.num) return strcmp(x.name,y.name)<0?1:0; //排名并列时,按账号的字母序升序输出。
	return x.num>y.num;//降序排序
}
int main(){
int n,x,num;
int sum=0;
cin>>n>>x>>num;
for(int i=1;i<=n;++i){
	scanf("%s %d",p[i].name,&p[i].num);
	if(p[i].num>=x) sum+=50;
	else if(p[i].num>=60) sum+=20;
}
printf("%d\n",sum);
sort(p+1,p+1+n,cmp);
//for(int i=1;i<=n;++i){
//	printf("%d %s %d\n",i,p[i].name,p[i].num);
//}
int paiming=1,ayy=0;
for(int i=1;i<=n-1;++i){
	if(p[i].num==p[i+1].num){
		printf("%d %s %d\n",paiming,p[i].name,p[i].num);
		ayy++;
	}
	else {
		printf("%d %s %d\n",paiming,p[i].name,p[i].num);
		paiming=paiming+ayy+1;
		ayy=0;
		if(paiming>num) break;
	}
} 
if(paiming<=num) printf("%d %s %d\n",paiming,p[n].name,p[n].num);
	return 0;
}

结构体排序

7-10 小字辈

#include <bits/stdc++.h>
#include <vector>
using namespace std;
vector<int>g[100100];
vector<int>ans;
int maxx=0;
int a;
void dfs(int x,int step){
	if(g[x].size()==0){
		if(step>maxx) {
			maxx=step;
			ans.clear();
			ans.push_back(x);
		}
		else  if(step==maxx) ans.push_back(x);//else 
	}
	for(int i=0;i<g[x].size();++i){
	dfs(g[x][i],step+1);
	}
}
 int main(void){
 	int n,x;
 	cin>>n;
 	for(int i=1;i<=n;++i) {
 		cin>>x;
 		if(x==-1)  a=i;
 		else //else 
 		g[x].push_back(i);
	 }
	 dfs(a,1);//dfs(-1,0)不行,因为是数组,下标不可能为-1
	 printf("%d\n",maxx);
	 sort(ans.begin(),ans.end());
	 printf("%d",ans[0]);
	for(int i=1;i<ans.size();++i) 
	printf(" %d",ans[i]);
 	return 0;
 }
牛客浙农林

瓜瓜的01串

#include <bits/stdc++.h>
using namespace std;
int main(void){
int n,k,sum1=0,sum0;
int ans=0;
cin>>n>>k;
string str;
cin>>str;
int len=str.size();
for(int i=0;i<len;++i){
	if(str[i]=='1') sum1++;
}
 //如果没有执行操作1
 //操作2和sum1的个数有关,如果操作数有多,并且是偶数,那么只要重复实现操作二在同一个字符上即可,
if(k<sum1) ans=max(ans,n-(sum1-k));
else ans=max(ans,n-(k-sum1)%2);
 //如果执行了操作1,那么k就要减个1,这时和sum0有关
 //如果操作数有多,那么只要重复实现操作一即可
if(k>=1){
	k--;
	sum0=n-sum1;
	if(k<sum0) ans=max(ans,n-(sum0-k));
	else ans=max(ans,n-(k-sum0)%2);
}
cout<<ans;
return 0;
}

因为偶数次的操作1等于没操作,所以操作1就可以转化成1次和0次。所以就分两种情况,一是执行了操作一的,另一个是没执行操作一的,然后两种情况取最值就行

策策学长找py

#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
struct peo{
	int x;
	int y;
}s[N];
bool cmp(peo x1,peo x2){
	if(x1.x==x2.x) return x1.y<x2.y?1:0;
	return x1.x<x2.x;
}
int main(void){
int t,n,m,k;
cin>>t;
while(t--){
	cin>>n>>m>>k;
	for(int i=1;i<=k;++i){
		scanf("%d%d",&s[i].x,&s[i].y);
	}
	int flag=1;
	sort(s+1,s+k+1,cmp);
	for(int i=1;i<=k-1;++i){
		if(s[i].y>s[i+1].y){
			cout<<"NO"<<'\n';
			flag=0;
			break;
		}
	}
	if(flag) cout<<"YES"<<'\n';
	
}
return 0;
}

我一开始用dfs,后来用dp,寄,建议以后写之间看看内存和时间

因为只能往右和往下走,所以考虑把他们的x进行排序,然后看y是不是升序即可(等于也可以),如果是,就yes

牛客上海理工

链接:https://ac.nowcoder.com/acm/contest/31389/D

#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
int f[50];
const int mod=1e9+7;
signed main(void) {
int n,k;//n代表第几项,k代表倍数;
cin>>n>>k;
int sum=0;
f[0]=1;
f[1]=k;
for(int i=2;i<=35;++i) f[i]=f[i-1]*k%mod;
for(int i=31;i>=0;i--){  //i从32开始就寄了
	if(n&(1<<i)) {
		sum=(sum+f[i])%mod;
		cout<<i<<" ";
	}
}
cout<<sum;
return 0;
}

感觉像是思维题,想的到用位运算就比较简单

天气预报

最近天上总会莫名其妙地下箭毒蛙,这太危险了,因此他只能在晴天出门,下箭毒蛙的日子就只能待在家休息,因此他查了查天气预报(Weather Report\textit{Weather Report}Weather Report),未来nnn天内的天气结果可以用一个长度为nnn的字符串表示,其中000表示晴朗,111表示会下箭毒蛙。Komorebi希望在这nnn天中选择连续\textbf{连续}连续的一段时间,也可以一天都不选,使得他在这段时间内至少可以出去玩aaa天,并且至少在家休息bbb天。

那么他一共有几种选法呢?

双指针的做法

//TLE的做法
#include <bits/stdc++.h>
using namespace std;
#define int long long 
signed main(){
    int n,a,b,ans=0;
    string str;
    cin>>n>>a>>b;
    getchar();
    getline(cin,str);
    for(int i=0;i<n;++i){
        int sum0=0,sum1=0;
        for(int j=i;j<n;++j){
        if(str[j]=='0') sum0++;
        if(str[j]=='1') sum1++;
        if(sum0>=a&&sum1>=b) {
            ans=ans+n-j;
            break;
        }
    }
    }
    if(!a&&!b) ans++;
    cout<<ans;
    return 0;
}



//所以时间复杂度怎么算,怎么感觉和我上面的复杂度差不多
//还有一种做法就是i往后移的时候,j不可能往前移的,即左边界往右移的时候,右边界不可能往左移    
#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int N=1e6+10;
int cnt[N];
int n,a,b,ans=0;
int check(int l,int r){
    int sum1=cnt[r]-cnt[l-1];
    int sum0=(r-l+1)-sum1;
    if(sum1>=b&&sum0>=a) return 1;
    return 0;
}
signed main(){
    string str;
    //cin>>n>>a>>b;
    scanf("%d%d%d",&n,&a,&b);
    getchar();
    getline(cin,str);
    cnt[0]=str[0]-'0';
    for(int i=1;i<n;++i){
        cnt[i]=cnt[i-1]+str[i]-'0';
    }
    int ans=0;
    for(int i=0,j=0;i<n;++i){
      while(j<n&&!check(i,j)) j++;
	   while(j<=n&&j<i) j++; //为什么int j=i 然后把这一行删掉不行呢
        //上面两行交换顺序并无大碍
        if(check(i,j)==1&&j<n) ans=ans+n-j;
    }
    if(!a&&!b) ans++;
    //cout<<ans;
    printf("%lld",ans);
    return 0;
}

次佛锅

你好阿,穿越题目前来的选手

众所周知backordinary不会次佛锅,所以邀请您来喂他。
佛锅是一串包含大小写英文字母、数字、空格的字符串。每个食材用单词加数字的方式表示,代表这个食材有多少个,例如yaxin 1代表有1个yaxin。每个食材间用空格隔开,相同食材可能多次出现。
backordinary每次会告诉你他想吃啥,需要你去锅里给他夹出来,他想知道每次他能吃到多少。

#include <bits/stdc++.h>
#include <map>
#include <cstring>
using namespace std;
map<string,int>mp; 
int main(void){
	string str;
	getline(cin,str);
	int len=str.size();
	for(int i=0;i<len;++i){
		int sum=0;
		string ans="";
        //判断是否是数字有一个函数的,isdigit
		if(str[i]!=' '&&isdigit(str[i])==0){
			while(str[i]!=' '&&isdigit(str[i])==0){
				ans=ans+str[i];//字符串相加的操作
				i++;
			}
        }
		if(str[i]==' ') i++;
			while(isdigit(str[i])){
				sum=sum*10+(str[i]-'0');
				i++;
			}
		//cout<<ans<<sum<<"\n";
		mp[ans]=mp[ans]+sum; 
	}
	int n;
	string ss;
	cin>>n;
	while(n--){
		cin>>ss;
		cout<<mp[ss]<<"\n";
	}
	return 0;
}


高级操作

#include <bits/stdc++.h>
using namespace std;
map<string, int>mp;
int main(void){
	while(cin.peek()!='\n'){
		string s;
		int num;
		cin>>s>>num;
		mp[s]=mp[s]+num;
	}
	int n;
	string str;
	cin>>n;
	while(n--){
		cin>>str;
		cout<<mp[str]<<"\n";
	}
}

peek()

  • 此函数返回输入流中的下一个字符,但是并不将该字符从输入流中取走——相当于只是看了一眼下一个字符,因此叫 peek。

  • cin.peek() 不会跳过输入流中的空格、回车符。在输入流已经结束的情况下,cin.peek() 返回 EOF。

  • 在输入数据的格式不同,需要预先判断格式再决定如何输入时,peek() 就能起到作用。

  • cin.peek()的返回值是一个char型的字符,其返回值是指针指向的当前字符,但它只是观测
    指针停留在当前位置并不后移;如果要访问的字符是文件结束符,则函数值是EOF(-1)

    cin.peek()的返回值是一个char型的字符,其返回值是指针指向的当前字符,但它只是观测
    指针停留在当前位置并不后移;如果要访问的字符是文件结束符,则函数值是EOF(-1)

cin.get()用来从指定的输入流中提取一个字符(包括空白字符),
函数的返回值就是读入的字符。若遇到输入流中的文件结束符,
则函数值返回文件结束标志EOF(End Of File),一般以-1代表EOF

叠硬币

Komorebi最近迷上了叠硬币的游戏。他先放一枚硬币在桌上,然后一枚一枚地往上堆,看能最多放几枚而不倒。
随着不断训练,Komorebi的技术也不断精进,但由于这样玩很费时间,很快他厌倦了这样的玩法。于是他想出了另一种玩法,先把硬币堆成一个个小堆,然后再把这些小堆叠起来,看最多能叠多高。
玩着玩着,Komorebi突发奇想:对于n个硬币堆,如果想选取一些硬币堆,一堆一堆地叠起来,将它们叠到正好H个硬币那样高(不可以随意增加或减少每个硬币堆的硬币数量),最少需要几个硬币堆呢?由于硬币堆太多了,他有些糊涂了,请你帮帮他吧!

第一行输出一个正整数m,表示达到高度H的最少硬币堆数。下面输出m个数代表该硬币堆的高度,并且方案按高度升序输出。如果有多个满足要求的方案(且都已按高度升序排列),则输出字典序最小的那个方案(如有两个长度都为m的序列A和B,若Ai=BiA_i=B_iAi=Bi,i=1,2,3,…,s(s<m)i=1,2,3,\ldots,s\left(s<m\right)i=1,2,3,…,s(s<m),且Ai+1<Bi+1A_{i+1}<B_{i+1}Ai+1<Bi+1,则认为序列A按字典序小于序列B)。如果没有任何一种方案可以正好达到高度H,就输出-1

#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int dp[3009][3009];
int a[N],ans[N];
int main(void){
	int m,h;
	cin>>m>>h;
	for(int i=1;i<=m;++i) cin>>a[i];
	sort(a+1,a+m+1);
	memset(dp,127,sizeof(dp));//0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))即可,实验了一下,发现写0x3f3f3f3f也是一样的,是1061109567,而写127,是2139062143
	dp[0][0]=0;
	for(int i=1;i<=m;++i){
		dp[i][0]=0;
		for(int j=0;j<=h;++j){
			 dp[i][j]=dp[i-1][j];
			if(j>=a[i]) dp[i][j]=min(dp[i][j],dp[i-1][j-a[i]]+1);
		}
	}
    //首先裸的dp要会写,初始化为0x3f3f3f3f,还有循环怎么写,循环内的初始化,都要会哦
if(dp[m][h]>=0x3f3f3f3f) cout<<-1;
else {
	cout<<dp[m][h]<<"\n";
	int j=1;
//从最大的开始找,类似于贪心,使他字典序最小
for(int i=m;i>=1;i--){
	if(a[i]<=h&&dp[i-1][h-a[i]]+1==dp[i][h]) {
		ans[j++]=a[i];
		h=h-a[i];
	}
}
for(int i=j-1;i>=1;--i) cout<<ans[i]<<" ";
}
}


//把dp变成一维数组的做法
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int dp[3009];
int a[N],ans[N];
int main(void){
	int m,h;
	cin>>m>>h;
	for(int i=1;i<=m;++i) cin>>a[i];
	sort(a+1,a+m+1);
	memset(dp,127,sizeof(dp));
	dp[0]=0;
for(int i=1;i<=m;++i){
	for(int j=h;j>=a[i];--j){
		dp[j]=min(dp[j],dp[j-a[i]]+1);
	}
}
if(dp[h]>=0x3f3f3f) cout<<-1;
else {
	cout<<dp[h]<<"\n";
	int j,k=1;
for(int i=1,j=h;i<=m;++i){
	if(dp[j-a[i]]+1==dp[j]) {
		ans[k++]=a[i];
		j=j-a[i];
	}
}
for(int i=1;i<k;++i) cout<<ans[i]<<" ";
}
}

浙大训练赛

题目大意:给你一些字符串,两两连接,问能连接成”BSUIROPENX“的有几种方案

#include <bits/stdc++.h>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <cstring>
using namespace std;
#define int long long
map<string,int>mp;
map<string,string>mpp;
set<string>ans;
signed main(void) {
int n;
string str="BSUIROPENX",s;
int len=str.size();
string ss="";
for(int i=0;i<len-1;++i){
	ss=ss+str[0];
	str.erase(str.begin());
	mpp[ss]=str;
}
//for(auto t:mpp){
//	cout<<t.first<<" "<<t.second<<"\n";
//}
scanf("%d",&n);
for(int i=1;i<=n;++i){
	cin>>s;
	mp[s]++;
}
int ans=0;
for(auto t:mp){
	ans=ans+t.second*mp[mpp[t.first]];
}
cout<<ans;
return 0;
}

题目大意:

给定两个字符串,让你求一个字符串,满足这个字符串删掉一个字符后可以变成给定的两个字符串,如果不存在,输出impossible

#include <iostream>
#include <cstring>
using namespace std;
void solve() {
	string a, b;
	cin >> a >> b;
	if (a == b) {
		cout << a << 'a';
		return ;
	}
	int l = 0, r = a.size() - 1;
	while (a[l] == b[l]) l++;
	while (a[r] == b[r]) r--;
	if (a.substr(l + 1, r - l) == b.substr(l, r - l)) {
		//a.insert(a.begin()+ r + 1, b[r]);
		//cout << a;
		cout << a.substr(0, r + 1) + b.substr(r, 1) + a.substr(r + 1);//第二个参数不写,表示截取到末尾
		return ;
	}
	swap(a, b);
	if (a.substr(l + 1, r - l) == b.substr(l, r - l)) {
		//a.insert(a.begin() + r + 1, b[r]);
		//cout << a;
		cout << a.substr(0, r + 1) + b.substr(r, 1) + a.substr(r + 1);
		return ;
	}
	cout << "IMPOSSIBLE";
}
int main(void) {
	solve();
	return 0;
}

2021浙江省赛 J. Grammy and Jewelry(完全背包+最短路(Dijkstra))

题目大意:给定n个顶点,m条边,时间t,然后每个顶点都有无限多的宝石,宝石的价值为a[i],然后每去一条边消耗的时间为1,从顶点1出发,要把宝石带回顶点才算获得该价值,问在t的时间里面,能获得的最大价值是多少

//这是我Dijkstra的板子
#include <stdio.h>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 5e5+10;
const int inf = 0x3f3f3f3f;
struct node{
	int to,w;
};
int m,n,s;
vector<node>g[maxn];
int dis[maxn];
bool vis[maxn];
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
void Dijkstra(){
	for(int i=1;i<=n;i++){
		vis[i]=false;
		dis[i]=inf;
	}
	dis[s]=0;
	q.push(make_pair(dis[s],s));
	while(!q.empty()){
		pair<int,int> now =q.top();
		q.pop();
		if(vis[now.second]) continue;
		vis[now.second]=true;//如果已经被访问过了就continue因为是优先队列,所以保证了先访问的一定是最短的,即已经求出了到某点的最短路径,队列剩下的都不是最短的了,continue即可
		for(int i=0;i<g[now.second].size();i++){
			//now.second->g[now.second][i].to
			int to=g[now.second][i].to;
			int w=g[now.second][i].w;
			if(dis[to]>dis[now.second]+w){
				dis[to]=dis[now.second]+w;
				q.push(make_pair(dis[to],to));
			}
		} 
	}
}
int main(void) {
scanf("%d%d%d",&n,&m,&s);//代表有n个顶点,m条边,问从s到每个顶点的最短路
for(int i=1;i<=m;++i){
	int u,v,w;
	scanf("%d%d%d",&u,&v,&w);//从u到v的距离是w
	g[u].push_back((node){v,w});//这里加了node()在vs上编译通不过,不过在dev上可以
	}
Dijkstra();
for(int i=1;i<=n;i++) printf("%d ",dis[i]);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 5e5+10;
const int inf = 0x3f3f3f3f;
int dp[maxn];
struct node{
	int to,w;
};
int m,n,s;
int t;
int a[maxn];
vector<node>g[maxn];
int dis[maxn];
bool vis[maxn];
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>q;
void Dijkstra(){
	for(int i=1;i<=n;i++){
		vis[i]=false;
		dis[i]=inf;
	}
	dis[1]=0;//顶点默认是1
	q.push(make_pair(dis[1],1));
	while(!q.empty()){
		pair<int,int> now =q.top();
		q.pop();
		if(vis[now.second]) continue;
		vis[now.second]=true;//如果已经被访问过了就continue因为是优先队列,所以保证了先访问的一定是最短的,即已经求出了到某点的最短路径,队列剩下的都不是最短的了,continue即可
		for(int i=0;i<g[now.second].size();i++){
			//now.second->g[now.second][i].to
			int to=g[now.second][i].to;
			int w=g[now.second][i].w;
			if(dis[to]>dis[now.second]+w){
				dis[to]=dis[now.second]+w;
				q.push(make_pair(dis[to],to));
			}
		} 
	}
}
int main(void) {
scanf("%d%d%d",&n,&m,&t);
for (int i = 2; i <= n ; ++i) scanf("%d", &a[i]);
for(int i=1;i<=m;++i){
	int u,v,w;
	scanf("%d%d",&u,&v);
	if (u == v) continue;
	g[u].push_back({v,2});//因为是来回,边权是2
	g[v].push_back({u,2});//这是无向图
	}
Dijkstra();
//for(int i=1;i<=n;i++) printf("%d ",dis[i]);
//下面就是完全背包问题
for (int i = 1; i <= n; ++i) {
	for (int j = dis[i]; j <= t; ++j) {
		dp[j] = max(dp[j], dp[j - dis[i]] + a[i]);
	}
}
for (int i = 1; i <= t; ++i) {
	cout << dp[i] << " ";
}
return 0;
}
leetcode

6128

思路,首先遍历suits,如果有两个不同就退出,如果全部相同return FLush

然后用map存数字,再遍历map记录maxx(出现的数字的最大次数)

class Solution {
public:
    string bestHand(vector<int>& ranks, vector<char>& suits) {
        int flag =1 ;
        for(int i=0;i<suits.size()-1;++i){
            if(suits[i]!=suits[i+1]) {
                flag=0;
                break;
        }
        }
        if(flag==1) return "Flush";
        map<int,int>mp;
        for(int i=0;i<ranks.size();++i){
            mp[ranks[i]]++;
        }
        int maxx=0;
        for(auto t:mp){
            if(t.second>maxx) maxx = t.second;
        }
        if(maxx>=3) return "Three of a Kind";
        else if(maxx>=2) return "Pair";
        else return "High Card";
    }
};

6129

class Solution {
public:
    long long zeroFilledSubarray(vector<int>& nums) {
        int cnt = 0;
        long long ans=0;
        int size = nums.size();
        long long  dp[100010]={0};//记录每个0对答案的贡献
        for(int i=1;i<=size;++i){
            dp[i]=dp[i-1]+i;
           // cout<<dp[i];
        }
        for(int i=0;i<size;++i){
            if(nums[i]!=0){
                ans=ans+dp[cnt];
                cnt=0;
               // printf("%d\n",ans);
            }
            else cnt++;
        }
        if(cnt!=0) ans=ans+dp[cnt];
        return ans;
    }
};

6130

class NumberContainers {
public:
    map<int,int>mp;
    NumberContainers() {
    }
    
    void change(int index, int number) {
        mp[index]=number;
    }
    
    int find(int number) {
        for(auto t:mp){
            if(t.second==number) return t.first;
        }
        return -1;
    }
};

/**
 * Your NumberContainers object will be instantiated and called as such:
 * NumberContainers* obj = new NumberContainers();
 * obj->change(index,number);
 * int param_2 = obj->find(number);
 */

2352

map里面套vector文章来源地址https://www.toymoban.com/news/detail-613820.html

class Solution {
public:
    int equalPairs(vector<vector<int>>& grid) {
        map<vector<int>,int>v;
        int ans = 0;
        for(int i=0;i<grid.size();++i){
            v[grid[i]]++;
        }
        for(int i=0;i<grid.size();++i){
            vector<int>cnt;
            for(int j=0;j<grid.size();++j){
                cnt.push_back(grid[j][i]);
            }
            if(v.count(cnt)) ans=ans+v[cnt];
        }
        return ans;
    }
};

到了这里,关于算法刷题记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java数据结构与算法刷题-----LeetCode287. 寻找重复数

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 弗洛伊德判圈法,也就是快慢指针判圈法(龟兔赛跑算法),此算法分为两个步骤 判断是否有环,并得到快慢指针相遇

    2024年01月24日
    浏览(38)
  • java数据结构与算法刷题-----LeetCode766. 托普利茨矩阵

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 这道题只要换一种理解方式,瞬间就会变的很简单。 题目描述是每个元素左上和右下对角线元素都相同。但是,我们发

    2024年01月25日
    浏览(45)
  • java数据结构与算法刷题-----LeetCode667. 优美的排列 II

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 题目要求我们返回一个数组长度为n的数组,必须含有1~n的所有数,并且从左到右,相邻的元素依次相减,它们的差,必

    2024年01月25日
    浏览(48)
  • java数据结构与算法刷题-----LeetCode240. 搜索二维矩阵 II

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 法一:把整个数组遍历一遍,时间复杂度O(m*n) 法二:每一行用二分搜索,那么时间复杂度就是O(m * l o g 2 n log_2{n} l o g

    2024年01月22日
    浏览(56)
  • java数据结构与算法刷题-----LeetCode209. 长度最小的子数组

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 代码:时间复杂度O(n).空间复杂度O(1)

    2024年01月21日
    浏览(48)
  • java数据结构与算法刷题-----LeetCode96. 不同的二叉搜索树

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难,但它就是固定套路而已。其实动态规划只不过是将多余的步骤,提前放到dp数组中(就是一个数组,只

    2024年01月21日
    浏览(52)
  • java数据结构与算法刷题-----LeetCode378. 有序矩阵中第 K 小的元素

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 解题思路 已知矩阵相对有序,可以用二分搜索,不过和一维数组排序不同,这是二维的 每一行都递增,每一列也是递增,所以每

    2024年01月23日
    浏览(49)
  • java数据结构与算法刷题-----LeetCode1091. 二进制矩阵中的最短路径

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 双分裂蛇:是求二维表中从起点到终点的经典思路(也是求无权图的最短路径问题的经典解法)。创建两条分裂蛇,分别从起点和

    2024年04月26日
    浏览(45)
  • DSt:数据结构的最强学习路线之数据结构知识讲解与刷题平台、刷题集合、问题为导向的十大类刷题算法(数组和字符串、栈和队列、二叉树、堆实现、图、哈希表、排序和搜索、动态规划/回溯法/递归/贪心/分治)总

    Algorithm:【算法进阶之路】之算法面试刷题集合—数据结构知识和算法刷题及其平台、问题为导向的十大类刷题算法(数组和字符串、链表、栈和队列、二叉树、堆、图、哈希表、排序和搜索、回溯算法、枚举/递归/分治/动态规划/贪心算法)总结 目录 相关文章

    2024年02月08日
    浏览(52)
  • 数据结构入门(C语言版)二叉树概念及结构(入门)

    1.1 树的概念 树是一种非线性的数据结构,它是由n(n=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。 ☆有一个特殊的结点,称为根结点,根节点没有前驱结点 ☆除根节点外,其余结点被分成M

    2023年04月14日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包