比赛传送门:https://ac.nowcoder.com/acm/contest/11216
A题
给你一堆向量和一个目标向量,问你这一堆向量中的某两个的和能不能得到和目标向量平行的向量。
首先回顾一下向量的加法(x1 , y1) + (x2 , y2) == (x1 + x2 , y1 + y2)
由于数据量较小,所以可以将所有的向量归一化,相当于都平移到原点,从原点开始。然后分别计算两两向量之和,判断是否和目标向量平行即可,即判断yy * ob.x == xx * ob.y 能用乘法就别用除法,会有精度问题!!!
AC代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool cmp(int a , int b){
return a > b;
}
struct node{
int x;
int y;
}a[1005];
int main() {
int t = 0;
int flag = 0;
cin>>t;
for(int i = 0 ; i < t ;i ++){
int x1 , y1 , x2 , y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
a[i].x = x1 - x2;
a[i].y = y1 - y2;
}
int X1 , X2 , Y1 , Y2;
scanf("%d%d%d%d",&X1,&Y1,&X2,&Y2);
node ob ;
ob.x = X1 - X2;
ob.y = Y1 - Y2;
for(int i = 0 ; i < t ; i ++){
for(int j = i + 1 ; j < t ; j ++){
int xx = (a[i].x + a[j].x);
int yy = (a[i].y + a[j].y);
if(yy * ob.x == xx * ob.y)
{
flag = 1;
break;
}
}
if(flag == 1)
break;
}
if(flag == 1)
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
return 0;
}
B题
签到,没什么说的
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool cmp(int a , int b){
return a > b;
}
int main() {
string s = "";
cin>>s;
int index = 0;
for(int i = 0 ; i < s.length() ;i ++){
if(s[i] == 'Q' && s[i+1] == 'A' && s[i+2] == 'Q'){
index = i;
break;
}
}
cout<<index + 1<<endl;
return 0;
}
C题
可以看成一个爬格子的问题,两个人的起点都为0,问你两个人最多同样大的次数(这道题主要难度在于读题)。解法很简单,只需要比较一下上一次的最大值和这一次的最小值的关系,如果上一次的最大值比这一次的最小值要小(或者等于),那么加上这两个的差值 + 1即可,否则什么也不加,如果上次两个人相等的话还要减1,因为这个相等的算了两次。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
int n = 0;
int ans = 0;
cin >> n;
static int a[3000005] = {0};
static int b[3000005] = {0};
for(int i = 1 ; i <= n ; i ++){
scanf("%d%d",&a[i],&b[i]);
}
for(int i = 1 ; i <= n ; i++){
ll x = max(a[i - 1] , b[i - 1]);//上一次最大的
ll y = min(a[i] , b[i]);//这一次最小的
if(x <= y)
ans += (y - x + 1);
if(a[i - 1] == b[i - 1])
ans --;
}
cout << ans << endl;
return 0;
}
E题
二进制计算问题,很简单,但是注意一下在计算的过程中使用long long,不然有可能爆整型
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool cmp(int a , int b){
return a > b;
}
int main() {
int n = 0;
cin>>n;
ll ans = 0;
while(n--){
int a[100005] = {0};
ll x = 0;
scanf("%lld" , &x);
int index = 0;
while(x != 0){
a[index] = x % 2;
index ++;
x /= 2;
}
int p = 0;
for(int i = index - 1 ; i >= 0 ; i --){
ans += (ll)(a[i] * (ll)pow(2 , p));//注意
p ++;
}
}
printf("%lld\n" ,ans);
return 0;
}
H题
前缀和算一下打到这里需要多少次斩杀(不用魔法),后缀和算一下打到这里需要多少次斩杀(不用魔法)。然后计算一下对任意两个相邻的使用魔法,还需要多少次斩杀,即计算 l[i] + r[i + 3]) 的最小值。注意循环开始和结束的下标。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
int a[N];
int b[N];
ll l[N];
ll r[N];
int main(){
int n = 0 ;
cin >> n;
for(int i = 1 ; i <= n ; i ++){
scanf("%d",&a[i]);
b[i] = a[i];
}
for(int i = 1 ; i <= n ; i ++){
l[i] = a[i] + l[i - 1];
a[i+1]=max(0,a[i+1]-a[i]);
a[i+2]=max(0,a[i+2]-a[i]);
}
for(int i = n ; i >= 1 ; i--){
r[i] = b[i] + r[i + 1];
b[i-1]=max(0,b[i-1]-b[i]);
b[i-2]=max(0,b[i-2]-b[i]);
}
ll ans = 2e18;
for(int i = 0 ; i + 3 <= n + 2; i ++)
ans = min(ans , l[i] + r[i + 3]);
cout<<ans<<endl;
return 0;
}