程序设计M4

本文分享了作者在算法竞赛中遇到的挑战与解决策略,包括使用不同数据结构优化性能,如set与unordered_set的选择,以及通过动态规划解决复杂问题的经验。

第一题错了4个,原因是因为用iostream没有取消同步,后来补题,也是很久才发现这点,
我是真的没有想到会卡这点的

TT数鸭子

在这里插入图片描述

样例输入
6 5
123456789 9876543210 233 666 1 114514
样例输出
4

解题思路

一开始我用的是set,但是错了4个点,超时
然后补题的时候,我继续用set,并且取消同步,多过了一个点
我想是set太慢了,所以我用了无序的set,结果又多过了一个点
但是这应该是set的极限了

然后我采用数组记录,取消同步后,800ms擦边过的

代码实现

#include<iostream>
#include<cstring>
using namespace std;
const int N = 1e6+10;
long long a[N];
int k,n;
bool b[10];

int main()
{
	ios::sync_with_stdio(0); 
	cin>>n>>k;
	for(int i=0;i<n;i++)  cin>>a[i];
	
	if(k==1){
		cout<<0<<endl; return 0;
	}
	if(k>10){
		cout<<n<<endl; return 0;
	}
	int c;
	int sum=0;
	int res=0;
	for(int i=0;i<n;i++)
	{
		while(a[i]!=0)
		{
			c = a[i]%10;
			a[i]/=10;
			b[c]=1;	
		}
		for(int j=0;j<10;j++)
		{
			if(b[j]) sum++;
		}
		if(sum < k) {
			res++;
		}
		sum=0;
		memset(b,0,sizeof b);
	}
	cout<<res<<endl;
	return 0;
}

ZJM要抵御宇宙射线

直接爆0,不多bb

在这里插入图片描述

解题思路

一开始,我没看到有 一个限制是 : 在点里面选圆心,结果gg了

后来补题的方法是,遍历所有点,算出两两之间的距离的最大值,并存起来
然后从最大值数组里面找出最小的那些
就是我们要的

非常要注意数值的大小
其中距离到最后几个点的时候,是超过了int 的,要用long long
并且输出的时候long long 要用 double

代码实现

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const long long inf = 1e15;
const int N = 1006;
int x,y,n;
int X[N],Y[N];
long long max_dis[N];
struct point{
	int x_,y_;
	long long dis;
	bool operator<(point t){
		if(x_!=t.x_) return x_<t.x_;
		if(y_!=t.y_) return y_<t.y_;
	}
};
point p[N];
int pi;

int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%d%d",&X[i],&Y[i]);
	
//	for(int i=0;i<n;i++) printf("%d%d ",X[i],Y[i]);	
	
	long long mt,dis;
	for(int i=0;i<n;i++)
	{
		mt = -1;
		for(int j=0;j<n;j++)
		{
			if(i==j) continue;
			dis = (long long)(pow(X[i]-X[j],2)+pow(Y[i]-Y[j],2));
			if(mt < dis) mt = dis; 
		}
		max_dis[i] = mt;
	//	printf("%lld ",max_dis[i]);
	}
	
	long long min_dis=inf;
	for(int i=0;i<n;i++)
	{
		if(max_dis[i]<min_dis) {
			min_dis = max_dis[i];
		}
	}
	
	for(int i=0;i<n;i++)
	{
		if(max_dis[i]==min_dis) {
			p[pi].x_=X[i],p[pi].y_=Y[i],p[pi].dis=min_dis;pi++;
		}
	}
	sort(p,p+pi);
	
	float xr,yr;
	double rr;
	xr = (float)(p[0].x_) , yr = (float)(p[0].y_) ,rr = (double)(p[0].dis) ;
	printf("%.2f %.2f\n",xr,yr);
	printf("%.2lf\n",rr);
	return 0;
}

宇宙狗的危机

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

解题思路

考试的时候,我想暴力出前5个点,但是时间还是不够了
没来得及调试就交了
结果直接编译失败了

之后看了别人的博客才知道这是个dp问题
状态方程 : 
dp[i][j][0]: 以i为根,j到i-1为左子树是否可以 (0\1)
dp[i][j][1]: 以i为根,i+1到j为右子树是否可以 (0\1)

转移方程:
dp[j+1][i][0] |=g[j+1][k]
dp[i-1][j][1] |=g[i-1][k]
[i,j]成立,且[i,k],[k,j]都成立,也就是k是根,i 到k-1是左子树,k+1到j是右子树。
往右扩展时,j+1是根,原来的树成了j+1的左子树。
往左扩展,i-1是根,原来的树成了i-1的右子树。

(dp太难了,自己确实写不出来)

代码

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N = 705;
int n,a[N];
bool g[N][N],dp[N][N][2];
int gcd(int a,int b){return b==0?a:gcd(b,a%b);}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(j==i) continue;
				if(gcd(a[i],a[j])>1) g[i][j]=1;
				else g[i][j]=0;
			}
		}
		
		for(int i=1;i<=n;i++) dp[i][i][0]=dp[i][i][1]=1;
		
		for(int j=1;j<=n;j++)
		{
			for(int i=j;i>=1;i--)
			{
				for(int k=i;k<=j;k++)
				{
					if(dp[k][i][0]&&dp[k][j][1]){
						dp[j+1][i][0]|=g[j+1][k];
						dp[i-1][j][1]|=g[i-1][k];
					}
				}
			}
		}
		bool flag=0;
		for(int i=1;i<=n;i++)
		{
			if(dp[i][1][0]&&dp[i][n][1]) {flag=1;break;}
		}
		if(flag) cout<<"Yes"<<endl;
		else cout<<"No"<<endl;
		memset(g,0,sizeof g);
		memset(dp,0,sizeof dp);
	}
	return 0;
}
本来以为这次会考得比较好的
结果t1一波超时
t2一波爆0
连t4的前5个点也没混到
直接炸裂
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值