第五次团体赛

B:3727:摘花生(DP)⭐⭐

描述
Hello Kitty 想摘点花生送给她喜欢的米老鼠。她来到一片有网格状道路的矩形花生地(如下图),从西北角进去,东南角出来。地里每个道路的交叉点上都有种着一株花生苗,上面有若干颗花生,经过一株花生苗就能摘走该它上面所有的花生。Hello Kitty只能向东或向南走,不能向西或向北走。问Hello Kitty 最多能够摘到多少颗花生。

输入
第一行是一个整数T,代表一共有多少组数据。1<=T <= 100
接下来是T组数据。

每组数据的第一行是两个整数,分别代表花生苗的行数R和列数 C ( 1<= R,C <=100)
每组数据的接下来R行数据,从北向南依次描述每行花生苗的情况。每行数据有 C 个整数,按从西向东的顺序描述了该行每株花生苗上的花生数目 M ( 0<= M <= 1000)。
输出
对每组输入数据,输出一行,内容为Hello Kitty能摘到得最多的花生颗数。
样例输入
2
2 2
1 1
3 4
2 3
2 3 4
1 6 5
样例输出
8
16
AC代码:
这题开局一看啊这不典型bfs嘛这我熟,然后…MLE,不死心,改战dfs,然后…TLE =_=
在带偏队友的路上一去不返…
各种LE了无数次后队友dp拿下
🤐🤐

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
int t,r,c;
const int N=110;
int val[N][N],dp[N][N];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&r,&c);
		for(int i=1;i<=r;i++)
		{
			for(int j=1;j<=c;j++)
				scanf("%d",&val[i][j]);
		}
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=r;i++)
		{
			for(int j=1;j<=c;j++)
			{
				dp[i][j]=max(dp[i-1][j],dp[i][j-1])+val[i][j];
			}
		}
		printf("%d\n",dp[r][c]);
	}
	return 0;
}

C - 换乘砖家 计蒜客 - T1401 (Dijkstra + 思维 + 建图)⭐⭐⭐

n个城市,编号为1~n,其中存在一些公交线路,现给出所有的公交线路,线路上左边的点可以通往右边的点,但是右边的无法到达左边的,问从1走到城市最少换乘几次?

输入格式
第一行:T 表示有多少组测试数据。(2 <= T <= 8)

接下来对每组测试数据:

第 1 行:M,N 表示有 M 条单程公交线路,共有 N 站。(1 <= M <= 100,1 <= N <= 500)

第 2 ~ M+1 行:每行描述一路公交线路信息,从左至右按运行顺序依次给出了该线路上的所有站号,相邻两个站号之间用一个空格隔开。

输出格式
对于每组测试数据,输出一行,如果无法乘坐任何线路从住处到达n城市,则输出"NO",否则输出最少换乘次数。

Sample Input
2
3 7
6 7
4 7 3 6
2 1 3 5
2 6
1 3 5
2 6 4 3
Sample Output
2
NO

AC代码:

我看不懂,但我大为震撼

这道题就是把每条线路上的点到它之后的所有点的边权设为1,最后迪杰斯特拉求最短路径减1。(这种思路让我想我可能这辈子都想不出来)(小声bb)

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int N=550;
const int INF=0x3f3f3f3f;
int t,m,n;
char a[N];
int b[N],head[N];
bool vis[N];
int dis[N];
int kk=0;

struct node
{
	int id,dis;
	bool operator < (const node & o)const
	{
		return dis>o.dis;
	}
};

struct edge
{
	int to,next,w;
}e[N*N];

void add(int u,int v,int w)
{
	e[kk].to=v;
	e[kk].w=w;
	e[kk].next=head[u];
	head[u]=kk++;
}

void Dijkstra()
{
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)	dis[i]=INF;
	
	priority_queue<node> q;
	dis[1]=0;
	q.push({1,0});
	
	while(!q.empty())
	{
		int nx=q.top().id;
		q.pop();
		
		if(vis[nx])	continue;
		vis[nx]=1;
		
		for(int i=head[nx];i!=-1;i=e[i].next)
		{
			int tx=e[i].to;
			if(dis[nx]+e[i].w<dis[tx])
			{
				dis[tx]=dis[nx]+e[i].w;
				if(vis[tx])	continue;
				q.push({tx,dis[tx]});
			}
		}
		
	}
	return;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&m,&n);
		getchar();	//读取回车 
		
		int cnt;
		kk=0;
		memset(head,-1,sizeof(head));
		while(m--)
		{
			cin.getline(a,520);	//读取一条线路上的所有站的标号 
			cnt=0;
			for(int i=0;i<strlen(a);i++)
			{
				if(a[i]!=' ')
				{
					int temp=a[i]-'0';
					i++;
					while(a[i]!=' '&&i<strlen(a))
					{
						temp=temp*10+a[i]-'0';
						i++;
					}
					b[cnt++]=temp;
				}
			} 
			
			//建图 
			for(int i=0;i<cnt;i++)
			{
				for(int j=i+1;j<cnt;j++)
					add(b[i],b[j],1);
			}
		}
		
		Dijkstra();
		if(dis[n]==INF)	printf("NO\n");
		else	printf("%d\n",dis[n]-1);
	}
	return 0;
}

D. Mocha and Hiking (思维)

题目链接
题目大意:有1 - (n+1)个村庄,1到n间的村庄与相邻的村庄都互相可达。
输入a[1]…a[n],如果a[i]=1表示可以从 n+1 到 i,如果a[i]=0表示可以从 i 到 n+1。
问能否不重复将所有点走一遍。
思路:
情况一:
情况一
。。。。就枚举各种情况就行辽

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int N=1e4+10;
int t,n,a[N];

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;i++)	scanf("%d",&a[i]);
		
		if(a[1]==1)	//n+1 -> 1 -> n 
		{
			printf("%d",n+1);
			for(int i=1;i<=n;i++)	printf(" %d",i);
			printf("\n");
		}
		
		else if(a[n]==0)	//1 -> n -> n+1
		{
			printf("%d",1);
			for(int i=2;i<=n+1;i++)	printf(" %d",i);
			printf("\n");
		}
		
		else
		{
			bool flag=0;
			for(int i=1;i<n;i++)
			{
				if(a[i]==1&&a[i+1]==0)	//n -> i+1 -> n+1 -> i -> 1
				{
					printf("%d",n);
					for(int j=n-1;j>=i+1;j--)	printf(" %d",j);
					printf(" %d",n+1);
					for(int j=i;j>=1;j--)	printf(" %d",j);
					printf("\n");
					flag=1;
					break;
				}
				
				else if(a[i]==0&&a[i+1]==1)	  //1 -> i -> n+1 -> i+1 -> n
				{
					printf("%d",1);
					for(int j=2;j<=i;j++)	printf(" %d",j);
					printf(" %d",n+1);
					for(int j=i+1;j<=n;j++)	printf(" %d",j);
					printf("\n");
					flag=1;
					break;
				}
			}
			if(flag==0)	printf("-1\n");
		}
	}
	return 0;
}

E. Strange Birthday Party(贪心)(思维)⭐

Pt准备举办一场Paty.他邀请了 n 位朋友,并且每位朋友和他的亲密关系为 k_i 。现在Pt给每一位朋友准备一份礼物。商店一共有 m 个礼物可选,第 j-th 个礼物价格为 c_j 元 ( 1 ≤ c_1 ≤c_2 ≤ … ≤ c_m ). 每件礼物最多只能买一次.

对于第 i-th 个朋友,Pt可以给他买第 j ≤ k_i 个价值 c_j 的礼物, 或者直接给他 c_{k_i} 元钱.

请求出Pt买礼物需要花费最少的钱.

∑ n ≤ 3*1e5

Input
第一行输入一个整数 t ( 1 ≤ t ≤ 10^3 ) ;表示测试用例

每组测试用例第一行输入两个整数 n and m ( 1 ≤ n, m ≤ 3 * 10^5 ) — 朋友的数量, 和商店礼物的数量.

接下来一行输入 n 个整数 k_1, k_2, …, k_n ( 1 ≤ k_i ≤ m ), 表示和Pt的亲密度

接下来一行输入 m 个整数 c_1, c_2, …, c_m ( 1 ≤ c_1 ≤ c_2 ≤ … ≤ c_m≤ 10^9 ) — 每个商品的价格.

Output
每个测试用例输出最小的价格.

Examples
Input

2
5 4
2 3 4 3 2
3 5 12 20
5 5
5 4 3 2 1
10 40 90 160 250
Output
30
190

AC代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=3e5+10;
int t,n,m;
int k[N],c[N];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)	scanf("%d",&k[i]);
		for(int i=1;i<=m;i++)	scanf("%d",&c[i]);	//本身升序排列 
		sort(k+1,k+n+1);
		int cnt=1;
		ll sum=0;	//注意范围 
		//贪心	
		for(int i=n;i>0;i--)	//给亲密度最高的分配最便宜的礼物(如果符合条件的话) 
		{
			if(cnt<k[i])	//如果最便宜的未分配礼物的价钱小于标号k[i]的价钱 
			{
				sum+=c[cnt];	//把这个礼物分配给亲密度为k[i]的那个朋友 
				cnt++;
			}
			else	//反之 
				sum+=c[k[i]];	//给他钱 
		}
		printf("%lld\n",sum);
	}
	return 0;
}

G - 协会的那点事 POJ - 2492 (种类并查集)⭐⭐⭐⭐⭐

Description
协会的同学有两个爱好,一类非常爱模拟题目,尤其喜欢做输出英文的模拟题,另一类很喜欢优化时长,每次遇到TLE都会变得异常兴奋,特别喜欢卡时间的毒瘤数据。
phz假定每个人都只与另一类人合作,这样就可以在写模拟的时候TLE了!但是你想看看到底是不是这样。
Problem
给出一个协会内合作的列表,请你判断是否有同种爱好的同学一起合作。

Input
输入的第一行包含数据的组数t,每组数据在第一行先给出人n的数量(至少一个,最多2000个),再给出实验数据的个数m(最多1000000个)用一个空格隔开。在下面m行中,每个实验数据以两个不同的人的编号给出,编号之间用一个空格来隔开

Output
每个输出包含"Scenario #i:",i为当前数据组数,如果phz的假设成立,另起一行输出“No suspicious bugs found!”,否则输出“Suspicious bugs found!”

Sample Input
2
3 3
1 2
2 3
1 3
4 2
1 2
3 4

Sample Output
Scenario #1:
Suspicious bugs found!

Scenario #2:
No suspicious bugs found!

AC代码:
确认过眼神,是我没学过的种类并查集

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=1e6+10;
int t,n,m;
int f[N];
int r[N];	// r[a]:f[a]-->a ,表示a与a父节点的关系。 
			//                (路径压缩后a直接与祖宗节点相连,也就表示(间接得出的)其与祖宗节点的关系) 
			//				   0表示同性,1表示异性 

int fd(int x)
{
	if(f[x]!=x)
	{
		//路径压缩 将所有点直接与祖宗节点相连 
		int temp=fd(f[x]);
		r[x]=(r[f[x]]+r[x])%2;
		//类似于向量相加 路径压缩后,r[x] : root-->x 
		//							 	<==> root-->f[x]-->x
		//								<==> r[f[x]+r[x] 
		f[x]=temp;
		return f[x];
	}
	return x;
}

int main()
{
	scanf("%d",&t);
	for(int kk=1;kk<=t;kk++)
	{
		scanf("%d%d",&n,&m);
		
		//初始化 
		bool flag=0;
		for(int i=0;i<=n;i++)
		{
			f[i]=i;	//每个点的父亲节点为自己 
			r[i]=0;	//每个点和自己同性 
		}
		while(m--)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			
			if(!flag)	//如果这个时候还没有找到bug 
			{
				int tx=fd(x);
				int ty=fd(y);
				// 寻找祖宗节点的同时路径压缩 
				
				if(tx==ty)		// 如果祖宗节点相同 
				{
					if(r[x]==r[y])	// 如果x、y与祖宗节点root的关系相同 
						flag=1;		// 比如同为1表示x与root异性、y与root异性,则x与y同性,可是又输入x、y异性,矛盾
									// 注意 即使r[x]或者r[y]=0,也只是表示推测出的(即路径压缩后)他们与祖宗节点的关系是同性,不代表原图相连的两个点为同性 
				}
				else
				{
					//合并操作 
					f[ty]=tx;	//将ty接于tx后面 
					r[ty]=(r[x]+1-r[y]+2)%2;
					// 	合并后 r[ty] : tx-->ty
					//				<==> tx-->x-->y-->ty
					//				<==> r[x]+1+(-r[y])
				}
			}
		}
		printf("Scenario #%d:\n",kk);
		if(flag)	printf("Suspicious bugs found!\n");
		else	printf("No suspicious bugs found!\n");
		if(kk!=t)	printf("\n");
	}
	return 0;
}

H-漫步森林(思维)

Problem Description
Gardon和小希每天晚上都喜欢到屋外的森林里散步,设森林里有N块空地,任意两块空地之间都有一条小径相通。他们每次从任意一块空地出发,经过所有的空地后回到原来的空地。
由于他们都喜欢新鲜的旅行,所以他们不希望对任何一条小径经过两次。那么请问,他们最多能保证多少次这种新鲜的旅行呢?
例如(图),当N=5时,他们只能保持两次这样新鲜的旅行。
Input
输入包含多组数据,每组数据占一行,是一个数字 N。(0<N<=1000000000)
文件以一个0结束。
Output
对于每个输入的N,输出最多能保证新鲜旅行的次数。
AC代码:
完全图,任一点出发,与其直接相连的点有n-1条,旅行一次废掉两条(去一条回一条),最多(n-1)/2 次。

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;
int main()
{
	while(cin>>n&&n)
		cout<<(n-1)/2<<endl;
	return 0;
}

I - 签到题 CodeForces - 1145A (思维

给定一个长度为 n 的数组,如果它不是非降序(非严格单调递增)的,那么就将它的前半部分或后半部分消灭。 不断重复这个消灭一半数组的过程,直至数组变为升序为止。 请问,得以幸存的数组的最大可能长度是多少?

Input
数据第一行包含整数 n。 第二行包含 n 个整数 a1,a2,…,an,表示给定数组。

Output
输出幸存数组的最大可能长度。

AC代码:
签到题因为忘了更新flag wa了好几发呜呜呜

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;

const int N=20;
int a[N];
int n;
bool flag;

int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)	scanf("%d",&a[i]);

	int maxx=1;
	for(int i=n;i>=1;i/=2)	//枚举长度 
	{
		flag=1;		//每种长度都更新flag=1,消除上种长度flag=0的影响 
		
		for(int j=1;j<=n;j+=i)	//枚举起点 
		{
			flag=1;		//每段都更新flag=1(不更新的话,就算有符合条件的 ,因为上段flag=0,所以这段也不会转为1 
			
			for(int k=j+1;k<j+i;k++)	//枚举起点到下一起点间的所有点 
			{
				if(a[k]<a[k-1])		//如果不是升序 
				{
					flag=0;
					break;	//这段不符合条件,break到下一段长度 
				}
			}
			
			if(flag)	//如果没有遇到不符合条件的,说明这段是升序 
			{
				maxx=i;
				break;
			}
			
		}
		if(flag)	break;
	}
	
	printf("%d\n",maxx);
	return 0;
}


K - 米奇妙妙屋 CodeForces - 1000B(思维+贪心??)⭐⭐⭐⭐

x那么np
他宿舍的灯有着一定规律,0时刻固定开灯,M时刻固定关灯,宿管老师会告诉你ta在0~M期间的哪些时刻会按下灯的开关,我们认为按一次开关则立刻会对此时灯的开关状态进行反转。
聪明的x找到了可以按下一次开关的机会,为了拥有更好的光照条件,x希望你帮ta分析一下,如果可以在任意两个时刻之间加入一次按开关的操作(也可以不加),那么这个灯亮着的最大时间是多少呢?

Input
第一行为两个整数n和M,表示宿管老师按开关的次数n和最终关灯的时刻M。(1≤n≤10^5, 2≤M≤10^9)
第二行为n个整数,表示宿管老师每次按下开关的时刻。

Output
输出一个数字,表示可能得到的灯亮的最长总时间

Examples
Input

3 10
4 6 7
Output
8

AC代码:

#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n,m;
ll a[N],kd[N];
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)	cin>>a[i];
	
	n++;
	a[0]=0;a[n]=m;kd[0]=0;
	
	int flag=1;
	for(int i=1;i<=n;i++)
	{
		kd[i]=kd[i-1]+flag*(a[i]-a[i-1]);	//记录每个点前的开灯时间(原始状态) 
		flag=!flag;
	}
	
	ll ans=kd[n];
	// 只能改变一个时刻的状态,为使灯亮时间最长,肯定是改变离a[i]+1/a[i]-1时刻的开关状态 
	for(int i=1;i<=n;i++)	//枚举改变a[i](左右)开关状态时灯亮的总时间 
		ans=max(ans,kd[i] + m-a[i]-(kd[n]-kd[i])-1);
		//	kd[i]表示a[i]前灯亮时间
		//	m-a[i]表示a[i]到m间的总时间
		//	kd[n]-kd[i]表示a[i]到a[n]间的总开关时间
		//	m-a[i] - (kd[n]-kd[i])表示原本状态a[i]到m间的关灯时间
		//	改变a[i](左/右)开关状态后 其后的开灯时间变为原本关灯时间-1 
	cout<<ans<<endl;
	return 0;
}


L - x的趣味问题 CodeForces - 1076A (思维)

如果我删除一个字母或者不删除字母,使这串单词的字典序最小,我应该删除哪一个?我删除之后的单词应该是什么?
Input
输入第一行包含一个整数n;第二行 是有n个字符组成的字符串。2<= n <= 2*10^5;
Output
输出一个字符串,表示可以通过删除一个或不删除的操作获得最小的在字典序字符串。
AC代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
const int N=2e5+10;
int n;
char a[N];
int main()
{
//	cin>>n>>a;TLE
	scanf("%d%s",&n,a);
	bool flag=0;
	int kk=strlen(a)-1;
	for(int i=0;i+1<n;i++)
	{
		if(a[i]>a[i+1])	//找到第一个降序字母 
		{
			kk=i;	//标记 
			break;
		}
	}
	for(int i=0;i<n;i++)
	{
		if(i==kk)	continue;
		printf("%c",a[i]);
	}
	printf("\n");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值