一些CF上的补题0504
知识点模块
1.通过三点计算三角形的面积可以这样写
area=fabs(x1*y2-x2*y1+x2*y3-x3*y2+x3*y1-x1*y3)/2;
2.最小公倍数与最大公约数
x×y=gcd(x,y)*lcm(x,y)
3.预处理非最小值每个点下一个的最小值的位置
for(int i=n,p=1e9;i>=1;i--)
{pos[i]=p;
if(ve[i]==minn) p=i;}
4.初始化一个有30位个1的二进制位
int a=(1<<30)-1
B. AND Sorting
这题我们发现将样例中的每个位置不匹配的按顺序与下去,得到的就是结果,猜一猜写一下,学习一下使用二进制数1111111111.....的初始化
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve()
{
int n;
cin>>n;
int ans= (1<<30) -1;//初始化一个很长的111111111
//其实他们的解释我也听不懂
//但是反正每个位置不同的数与一下就是样例的结果
//猜着猜着来吧
for(int i=0;i<n;i++)
{
int x;
cin>>x;
if(x!=i) ans&=x;
}
cout<<ans<<endl;
}
signed main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
C. 3SUM Closure
1.假如有n个数,里面至少有3个数a>b>c>0,那么a+b+c>a是肯定的,这个元素肯定不符合题意,那么三个负数也是同理的。
2.我们注意到当三个数为0 0 x的时候,无论你的x是任何数,都是符合题意的,那么如果有很多个0和x,只需要取1个0,怎么理解呢,如果我们是-2,2,0,0其实和-2 2 0是等价的,举其他例子也是同理。
3.综上,我们其实最多只能取到两个正数,两个负数和一个0的情况,为什么一定要有1个0呢?因为我举不出来没有0可以符合的情况。
所以我们只需要检查一下,有没有0,检查一下有几个正数负数,检查完以后再暴力遍历验证一下就可以
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve()
{
int n,markz=0,markf=0,zero=0,check=1;
cin>>n;
vector<int>ve;
map<int,int>mp;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
if(x>0) {
if(++markz<3) ve.push_back(x),mp[x]=1,check=0;
}
else if(x<0)
{
if(++markf<3) ve.push_back(x),mp[x]=1,check=0;
}
else if(++zero==1) ve.push_back(x),mp[x]=1;
}
//如果有三个及以上正数或者三个及以上负数都不符合
//因为a+b+c>a(a最大) 负数同理
//由于0 0 x当x取任何数都符合情况,所以当有多个0的时候,我们只需要把一个放入数组即可
if(markz>=3||markf>=3) {
cout<<"NO"<<endl;
return ;
}
if(check==1) {
cout<<"YES"<<endl;
return;
}
for(int i=0;i<ve.size();i++)
{
for(int j=i+1;j<ve.size();j++)
{
for(int k=j+1;k<ve.size();k++)
{
if(mp[ve[i]+ve[j]+ve[k]]==0) {
cout<<"NO"<<endl;
return;
}
}
}
}
cout<<"YES"<<endl;
}
signed main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
H. Fight Against Monsters
本质上其实是一个贪心的问题,当时我想的是用前缀和来减少时间复杂度,但是这样还是会超时,所以改变一下记录代价的思维,记录每个怪物攻击的次数,最后一步计算总代价的时候直接加上去大概就是O(n)的复杂度,我们排序的时候要注意结合次数和攻击来排序,并不是攻击力越大的排在越前面,举个例子4 5和3 2,代码有注解
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int swj=1;
typedef pair<int,int>pii;
struct a{
int hp;
int atk;
int cnt;
}ve[100005];
int num(int x)//计算杀死一个怪物要几次
{
int sum=0,cnt=1;
while(x>0)
{
sum++;
x-=cnt++;
}
return sum;
}
bool cmp(a xx,a yy){
return xx.atk*yy.cnt>yy.atk*xx.cnt;//并不是伤害大就排前面 要结合出现次数
}
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>ve[i].hp>>ve[i].atk;
int x=ve[i].hp;
ve[i].cnt=num(x);//num用来计算杀死这个怪物要几次
}
sort(ve+1,ve+n+1,cmp);
//与我思路不同在于最小代价的计算人家是算每个怪物的总次数
//比如样例1攻击力6次 2攻击了4次 3攻击了2次 代价为19
int ans=0,cntt=0;
for(int i=1;i<=n;i++)
{
cntt+=ve[i].cnt;
ans+=cntt*ve[i].atk;
}
cout<<"Case #"<<swj++<<": ";
cout<<ans<<endl;
}
signed main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
B. Nana Likes Polygons
湖北省赛B题,我们要凸多边形的最小值,那么就是三角形,只要通过暴力遍历输入的点找最小值并更新即可,如果找不到最小值就是0,注意输出的时候要开到小数点后6位,不然是过不去的,还有注意更新最小值的条件
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int>pii;
void solve()
{
int n;
cin>>n;
vector<pii>ve(n+1);
for(int i=1;i<=n;i++)
{
cin>>ve[i].first>>ve[i].second;
}
double minn=1e15;
bool check=0;
for(int i=1;i<=n-2;i++)
{
for(int j=i+1;j<=n-1;j++)
{
for(int k=j+1;k<=n;k++)
{
int x1=ve[i].first,y1=ve[i].second;
int x2=ve[j].first,y2=ve[j].second;
int x3=ve[k].first,y3=ve[k].second;
double area=fabs((x1*y2+x2*y3+x3*y1-x1*y3-x3*y2-x2*y1)/2.0);
//若无法构成三角形就是0
if(area>0)
{
minn=min(minn,area);
check=1;
}
//cout<<area<<endl;
}
}
}
if(!check) cout<<-1<<endl;
else printf("%.7lf\n",minn);
}
signed main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
A. Long Live
x×y=gcd(x,y)*lcm(x,y),那么把这坨代入进去以后就是a ^ 2×b=x×y/gcd(x,y)^2,把a除过去,当a最小时ab最大,因为a只会是整数,所以a为1时这就成立了,而左边的这坨是可以算出来的定值
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve()
{
int x,y;
cin>>x>>y;
int fm=gcd(x,y);
cout<<1<<" "<<(x*y)/(fm*fm)<<endl;
}
signed main()
{
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
E. Equality
这一题本质上也是个贪心的问题,但是遇到的类型比较奇特,所以要学习一下,理解完题意以后我们可以这样做,第一步,先找所有数字里面的最大值和最小值,若最大值等于最小值说明数字全都相等没有答案,若有最大值和最小值,便再看k是否为1,若为1,也不符合题意,符合题意以后,我们大概的思路就是枚举左端点,若左端点为最小值则跳过,下标++,若不是最小值,我们检查这个端点的下一个最小值的位置是否合法,若合法更新下标,不合法则往左退一位再更新下标,因为此时左边已经全为最小值
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int n,k;
int maxx=-1,minn=1e9;
cin>>n>>k;
vector<int>ve(n+1);
for(int i=1;i<=n;i++)
{
cin>>ve[i];
maxx=max(ve[i],maxx);
minn=min(ve[i],minn);
}
if(maxx==minn) cout<<0<<endl;
else {
if(k==1) cout<<"-1"<<endl;
else {
vector<int>pos(n+1,1e9);
//预处理每一数字的最小值的下一个位置
for(int i=n,p=1e9;i>=1;i--){
pos[i]=p;
if(ve[i]==minn) p=i;
}
int sum=0;
for(int i=1;i<=n;i++)
{
if(ve[i]==minn) continue;
sum++;
//检查不为最小值的点的下一个最小值的位置是否合法,如果可以直接换下标
//如果不可以,则左端点往左移一格
if(pos[i]>=i+k) i--;
i+=k-1;// + k-1是因为更新完后i会自己++ 如果是+k就会跳过一个点
}
cout<<sum<<endl;
}
}
}
signed main(){
int t=1;
cin>>t;
while(t--) solve();
return 0;
}
J. Points on the Number Axis A
这题还没理解,还得问问再补
L. LCMs
这题也还没理解,还得补
posted on 2024-05-04 23:55 swj2529411658 阅读(48) 评论(3) 编辑 收藏 举报