第二次训练赛
leetcode上的题目
题意:
给定n个点的坐标,你可以按照任意顺序,把坐标值加到一块,每一个坐标最多用一次(每一个坐标可以使用一次,或者不使用),要求得到的坐标值离原点最远。
思路:
将每一个点当作一个向量的坐标,两个向量相加,夹角越小,想加形成的向量和的模长越长。
所以,可以将这些向量按照极角排序
#include<bits/stdc++.h>
#include<cmath>
using namespace std;
typedef long long ll;
const int N = 110;
struct node{
ll x,y;
}r[N];
//ll nx[N];
bool cmp(node a,node b)
{
return atan2(a.y,a.x)<atan2(b.y,b.x);
}
int main()
{
ll n;
cin>>n;
for(ll i=1;i<=n;i++) cin>>r[i].x>>r[i].y;
sort(r+1,r+n+1,cmp);
ll nx[N];//用于循环
for(ll i=1;i<=n;i++) nx[i]=i+1;
nx[n]=1;
ll ans=0;
for(ll i=1;i<=n;i++)
{
ll X=r[i].x,Y=r[i].y;
ans=max(ans,X*X+Y*Y);
for(ll j=nx[i];j!=i;j=nx[j])
{
X+=r[j].x;
Y+=r[j].y;
ans=max(ans,X*X+Y*Y);
}
}
printf("%.10lf\n",sqrt(ans));
return 0;
}
题意:
给定一个长度为n的数列,将这个数列分成连续并且长度为k的子串
问?最多能分出多少个这样的子串
思路:
总共n-k+1个
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,k;
cin>>n>>k;
cout<<n-k+1<<endl;
return 0;
}
题意:
给定一个整数n,从1~n建立一个数组 a[i]=i;
对这个数组重新排序,使得 数值%下标的和最大
思路:
数值:13 1 2 3 4 5 6 7 8 9 10 11 12
下标:1 2 3 4 5 6 7 8 9 10 11 12 13
结果最大为:0+1+2+3+4+5+6+7+8+9+10+11+12;
这个题走了很多坑
刚开始用暴力写出了结果,但是n的数值1e9 所以超时了
结果又想了很多种什么时候取得最大的情况,但是多错了
最后我用暴力写出的代码得到了重新排列后的数组,然后得知上诉情况取得最大值。
错误代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 0x3f3f3f3f;
bool vis[N];
int main()
{
ll n;
cin>>n;
ll ans=0;
for(ll i=1;i<=n;i++)
{
ll mod=0;
for(ll j=1;j<=n;j++)
{
if(!vis[j])
{
if(i%j>mod)
{
vis[j]=1;
mod=i%j;
}
}
}
ans+=mod;
}
cout<<ans<<endl;
return 0;
}
正确代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e9+10;
int main()
{
ll n;
cin>>n;
ll ans=0;
for(int i=1;i<=n-1;i++)
ans+=i;
cout<<ans<<endl;
return 0;
}
题意:
给出n个怪物的生命值, 一个随机的活的怪物攻击另一个随机的活的怪物。
被攻击的生命值的减少量等于当前正在攻击的怪物的生命值,而攻击者的生命值不变.
思路:
求出n个数的GCD
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int a[N];
int main()
{
int n;
cin>>n;
int gcd;
int x;
cin>>x;
gcd=x;
for(int i=2;i<=n;i++)
{
cin>>x;
gcd=__gcd(gcd,x);
}
cout<<gcd<<endl;
return 0;
}
题意:
有n个商品,有m张打折券,打折的具体规定为 :物品单价X,打折券的个数为Y, 打完折后物品的单价为 X/2^Y;
这m张打折券如果分配,最后n个商品的总价格最低
思路:
从最高的价格进行打折,最高价格的商品打完折后的价格为X=Xmax/2, 对最高的价格用一张券,每次都更新这n个商品的价格,每次都选择当前商品价格最高的商品进行打折券的使用.
运用优先队列(从大到小排列)进行存放物品的单价,每次取队首/=2,在将其压进队列,重复此操作,一直到m张打折券用完.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//每次都选出最大的那一个数除以2
int main()
{
int n,m;
ll ans=0;
cin>>n>>m;
priority_queue<int>que;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
que.push(x);
}
for(int i=0;i<m;i++)
{
que.push(que.top()/2);
que.pop();
}
while(!que.empty())
{
ans+=que.top();
que.pop();
}
cout<<ans<<endl;
return 0;
}
题意:
n,k,Q
给定一个长度为n的数组a[n],并且所有的值都为k,
输入k个数,这k个数是数组的下标,说明:::当k个数中的其中一个数为2时,说明a[2]不变,其他的数值都减一。
if a[i]的值<=0 输出“NO”;
else 输出“Yes”:
思路:
记录k个数的每一个数的个数 ,得到 k-(Q-mp[i])进行判断
#include<bits/stdc++.h>
using namespace std;
const int N =100010;
int b[N];
int vis[N];
int main()
{
int n,k,q;
cin>>n>>k>>q;
memset(vis,0,sizeof(vis));
int id;
for(int i=1;i<=q;i++) cin>>id,vis[id]++;
for(int i=1;i<=n;i++)
{
b[i]=k;
b[i]=b[i]-(q-vis[i]);
if(b[i]>=1) puts("Yes");
else puts("No");
}
return 0;
}
题意:
给定一个长度为n的数组,每一个数值当作楼梯的高度,如果后边的数值小于当前的数值,则前进一步,问::最多能前进几步?
思路:
从左往右进行遍历,每次都更新找到最大的step。
注意:如果后面几个楼梯的高度都能往下走,最后必须要记录最后的那个走的步数进行step(max)的选取。
因为只有走到右边的数大于当前的数,才会停止得到当前的res,最后一直走下去则找不到最后的res,所以,要进行一个记录。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
ll a[N];
bool b[N];
int main()
{
ll n;
cin>>n;
a[0]=0;
ll ans=0;
ll res=0;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]>a[i-1])
b[i]=0;
else
b[i]=1;
}
ll flag=0;
for(ll i=1;i<=n;i++)
{
if(b[i])
{
res++;
flag=res;
}
else
{
ans=max(ans,res);
res=0;
}
}
cout<<max(ans,flag)<<endl;
return 0;
}
题意:
给定一个长度为n的数组,并且复制k次,如果前面的数大于右边的数就ans+=1;求得最后的ans
思路:
在长度为n的数组中,找到当前位置右边的数小于当前位置数的个数,左边的数大于当前位置的数的个数。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 10000;
ll a[N];
ll r[N],l[N];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
ll n,k,ans;
cin>>n>>k;
for(ll i=1;i<=n;i++) cin>>a[i];
ll num=0;
num=(k+1)*k/2;
num-=k;
num%=mod;
ans=0;
memset(r,0,sizeof(r));
memset(l,0,sizeof(l));
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<i;j++)
{
if(a[i]>a[j])
l[i]++;//这个数左边小于当前位置的数的个数
}
for(ll j=i+1;j<=n;j++)
{
if(a[i]>a[j])
r[i]++;//这个数右边小于当前位置的数的个数
}
}
// cout<<num<<endl;
for(ll i=1;i<=n;i++)
{
// cout<<l[i]<<' '<<r[i]<<endl;
ans=ans+l[i]*num%mod;
ans=ans+r[i]*(num+k)%mod;
}
cout<<ans%mod<<endl;
return 0;
}
题意:
将n个字符串组成一个字符串,问如何分配才能得到最多的含有“AB”的个数?
思路:
求得a=······A,b=B·····字符串的个数,res=min(a,b),在求出每一个字符串中含有“AB”的个数进行加和。
注意:
当两个字符串都为 B····A,则最后的答案为1
所以要将这种特殊情况在最后的答案中减去1
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N= 100100;
string s[N];
//map<int,map<char,char>>mp;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
ll n;
cin>>n;
int t;
ll res;
map<char,ll>m;
map<char,ll>p;
int flag=0;
for(ll i=0;i<n;i++)
{
cin>>s[i];
m[s[i][0]]++;
p[s[i][s[i].size()-1]]++;
if(s[i][0]=='B'&&s[i][s[i].size()-1]=='A')
flag++;
}
ll a=m['B'],b=p['A'];
ll c=a-flag,d=b-flag;
ll ans=0;
for(ll i=0;i<n;i++)
{
t=s[i].size();
for(ll j=0;j<t;j++)
{
if(s[i][j+1]=='B'&&s[i][j]=='A')
ans++;
}
}
res=min(b,a);
ans+=res;
// cout<<flag<<endl;
// cout<<ans<<endl;
if(c==0&&d==0&&flag!=0) ans--; //当给定的字符串中都是以B开头 以A结尾的字符串,最后的结果需要减去1
cout<<ans<<endl;
return 0;
}