文章目录
A . Exact Change
大意:
给出一个集合,找出这个集合的子集和最小的不能表示的数
思路:
一开始以为是个 背包问题 , 但是爆了时间又爆了空间 ,最后是 qzp 想出来的思路
我们假设现在我们最大的可表示的数是
k
k
k,可表示的数的区间是
[
0
−
k
]
[0-k]
[0−k],我们想要用已知的数扩大这个区间,每次要找一个 数
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]
[0−k+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]
[0−k]U[k+2−k+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);
}
}
最后祝大家补题愉快