UCF(2022暑期团队赛三)

A . Exact Change

大意:

给出一个集合,找出这个集合的子集和最小的不能表示的数

思路:

一开始以为是个 背包问题 , 但是爆了时间又爆了空间 ,最后是 qzp 想出来的思路
我们假设现在我们最大的可表示的数是 k k k,可表示的数的区间是 [ 0 − k ] [0-k] [0k],我们想要用已知的数扩大这个区间,每次要找一个 数 s s s 满足 ( s < = k + 1 ) (s<=k+1) (s<=k+1),使得这个数可以与可表示区间接起来,使得最大可表示的数 k k k 更新为 k + s k+s k+s,可表示数的区间变为 [ 0 − k + s ] [0-k+s] [0k+s],如果 s s s不满足条件,比如 s s s等于 k + 2 k+2 k+2 ,那可表示的区间就是 [ 0 − k ] U [ k + 2 − k + s ] [0-k]U[k+2-k+s] [0k]U[k+2k+s],漏掉了 k + 1 k+1 k+1,所以当有数不满足 ( s < = k + 1 ) (s<=k+1) (s<=k+1)这个条件时, k + 1 k+1 k+1 既是我们要找的那个数,当然了 ,我们一开始要对整个集合排序,以保证我们思路的正确性

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

int t,n;
int a[101],cnt;

int main()
{
	cin>>t;
	
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n;i++) cin>>a[i];
		sort(a+1,a+1+n);
		int now=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i]<=now+1) now+=a[i];
			else break;
		}
		printf("Set #%d: %d\n\n",++cnt,now+1);
	}
}

C . Fold the Paper Nicely

大意:

给出 两个数 ,处理 n 次 ,每次处理 把较大的数除2,运算到都为 0 或者 次数为 0 为止,输出时大数在前小数在后;

思路

写个循环

#include<bits/stdc++.h>
using namespace std;
int a,b,n;
int main()
{
	cin>>a>>b>>n;
	while(a+b)
	{
		if(a>=b) a/=2;
		else b/=2;
		n--;
		if(n==0) break;
	}
	cout<<max(a,b)<<" "<<min(a,b);
}

F . Call Me Maybe

大意:

给出 n 句话,然后给出一次询问,要求用话中的单词组成询问的句子,若询问的某个单词在询问中出现多次,而在话中有多个不同的位置,按顺序依次输出每个位置

思路:

把话中每个单词对应的所有位置存下来,然后先判断是否能组成询问句子,能的话依次输出位置即可,细节看代码

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

int t,n,m;
string ss;
typedef pair<int,int>PII;

map<string,vector<PII>>mp;//存每个单词对应位置
map<string,int>mp1;//记录询问中每个单词第几次出现
string s[51];

int main()
{
	cin>>t;
	
	for(int i=1;i<=t;i++)
	{
		cin>>n;
		for(int j=1;j<=n;j++)
		{
			cin>>ss;
			mp[ss].push_back({i,j});
		}
	}//先把每个单词所有位置记下来
	
	cin>>m;
	
	for(int i=1;i<=m;i++)
	{
		cin>>s[i];
		if(mp[s[i]].size()==0)
		{
			cout<<"NOT POSSIBLE";
			return 0;
		}
	}//判断是否能组成
	
	for(int i=1;i<=m;i++)
	{
		mp1[s[i]]++;
		int k=mp1[s[i]];//k表示这个单词在询问中第 k 次出现
		n=mp[s[i]].size();//n 表示这个单词在话语集中出现次数
		cout<<mp[s[i]][(k-1)%n].first<<" "<<mp[s[i]][(k-1)%n].second<<endl;
	}//能组成的话依次输出位置
}

H . Rummy Score

大意:

给出 7 个数 ,超过三个以上连续的数和超过三个以上相同的数可以消掉,问操作后的最小剩余数和是多少

思路:

看大家都是 dfs 做的,我当时是硬写的
首先 判断消去连续数还是相同数,我的思路是两种都试试,第一种先处理连续的再处理相同的,第二种先处理相同的在处理连续的,取剩余和小的即可,但是

4 5 6 6 6 6 13
13

这种情况是一半连续一半相同,我们要特殊处理这种情况,这种情况的特点就是有一个数出现了四次,然后有两个以上的数与出现四次的数组成了连续,这时候我们要把四个数 拆成 三个 和 一个,尽可能多消去

#include<bits/stdc++.h>
using namespace std;
const int N = 1e2+10;

int a[10],sum,key,sum1,sum2;
map<int,int>mp;
map<int,int>mp1;
map<int,int>mp2;

int solve2()
{
	mp1=mp;mp2=mp;
	sum1=sum;sum2=sum;
	for(auto k : mp1)
	{
		if(k.second>=3)
		{
			sum1-=k.first*k.second;
			mp1[k.first]=0;
		}
	}
		
	for(auto k : mp1)
	{
		while(k.second>=1)
		{
			int s=k.first,ss=k.first;
			while(mp1[s+1]!=0) s++;
			
			if(s-k.first>=2)
			{
				for(int i=ss;i<=s;i++)
				{
					sum1-=i;
					mp1[i]--;
				}
			}
			else break;
		}
	}//先处理相同,在处理连续
	
	for(auto k : mp2)
	{
		while(k.second>=1)
		{
			int s=k.first,ss=k.first;
			while(mp2[s+1]!=0)	s++;
			
			if(s-k.first>=2)
			{
				for(int i=ss;i<=s;i++)
				{
					sum2-=i;
					mp2[i]--;
				}
			}
			else break;
		}
	}
	
	for(auto k : mp2)
	{
		if(k.second>=3)
		{
			sum2-=k.first*k.second;
			mp2[k.first]=0;
		}
	}//先处理连续,在处理相同
	
	
	return min(sum1,sum2);
}

int solve1()
{
	if(mp[key-1]&&mp[key-2]) return sum-key*6+3;
	else
	if(mp[key+1]&&mp[key+2]) return sum-key*6-3;
	else return solve2();
}

int main()
{
	for(int i=1;i<=7;i++) cin>>a[i],sum+=a[i],mp[a[i]]++;
	sort(a+1,a+1+7);
	
	bool flag=0;
	
	for(auto k : mp)
	{
		if(k.second==4) flag=1,key=k.first;
	}
	
	if(flag) cout<<solve1();
	else 	cout<<solve2();	
}
反思:

在处理连续的时候,还是比较麻烦的,要在 map 种进行处理 ,因为在数组中排序后会有

8 8 9 9 10 10 10

这种情况,相邻不连续但是存在连续,在马 map 中相邻连续,所以在map 中处理,比较麻烦,嫌麻烦的可以去看看 dfs 思路

I . Simi Circles

大意:

给出 n 个圆,每个圆有可能与前后两个圆相交,问相交圆的总面积大小

思路:

相交圆面积问题

模板:
#include<iostream>
#include<cmath>
using namespace std;
#define pi acos(-1.0)

int t,n;
int cnt;
struct node{
	double x;
	double y;
	double r;
}a[1001];
 
double area(node a,node b)
{
	double r1=a.r,r2=b.r;
	double d = sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
	if (d >= r1+r2)
		return 0;//相离
	if (r1>r2)
	{
		double tmp = r1;
		r1 = r2;
		r2 = tmp;
	}
	if(r2 - r1 >= d)
		return pi*r1*r1;//相交
	double ang1=acos((r1*r1+d*d-r2*r2)/(2*r1*d));
	double ang2=acos((r2*r2+d*d-r1*r1)/(2*r2*d));
	return ang1*r1*r1 + ang2*r2*r2 - r1*d*sin(ang1);
}
实现思路:

相交圆

#include<iostream>
#include<cmath>
using namespace std;
 
#define pi acos(-1.0)

int t,n;
int cnt;

 
struct node{
	double x;
	double y;
	double r;
}a[1001];
 
double area(node a,node b)
{
	double r1=a.r,r2=b.r;
	double d = sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
	if (d >= r1+r2)
		return 0;//相离
	if (r1>r2)
	{
		double tmp = r1;
		r1 = r2;
		r2 = tmp;
	}
	if(r2 - r1 >= d)
		return pi*r1*r1;//相交
	double ang1=acos((r1*r1+d*d-r2*r2)/(2*r1*d));
	double ang2=acos((r2*r2+d*d-r1*r1)/(2*r2*d));
	return ang1*r1*r1 + ang2*r2*r2 - r1*d*sin(ang1);
}
 
int main()
{
	cin>>t;
	
	while(t--)
	{
		cin>>n;
		double sum=0;
		for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y>>a[i].r;
		
		if(n==1)
		{
			sum+=pi*a[1].r*a[1].r;//一定注意特判只有一个圆的情况
		}
		else
		{
			sum+=pi*a[1].r*a[1].r;
			for(int i=2;i<=n;i++)
			{
				sum+=(pi*a[i].r*a[i].r-area(a[i],a[i-1]));
			}	
		}
		printf("Set #%d: %.2lf\n\n",++cnt,sum);
	}
}

最后祝大家补题愉快

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

QiWen.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值