A. Too Min Too Max
题面:
给定由 n 个元素组成的数组 a,求表达式的最大值:
∣
a
i
−
a
j
∣
+
∣
a
j
−
a
k
∣
+
∣
a
k
−
a
l
∣
+
∣
a
l
−
a
i
∣
|a_i - a_j| + |a_j - a_k| + |a_k - a_l| + |a_l - a_i|
∣ai−aj∣+∣aj−ak∣+∣ak−al∣+∣al−ai∣
其中, i、 j、k、l 是数组 a 的四个不同的索引,其中
1
≤
i
,
j
,
k
,
l
≤
n
1 \le i, j, k, l \le n
1≤i,j,k,l≤n。
这里的 |x| 表示 x 绝对值。
思路:因为n的数据范围是>=4,所以直接升序排序然后进行操作就行了。以|最大-最小| + |最小-次大| + |次大 -次小| + |次小-最大|
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
const int N=1e6+10;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
#define int long long
void solve()
{
int n; cin >> n;
int a[N];
for(int i=1;i<=n;i++) cin >> a[i];
sort(a+1,a+n+1);
cout << abs(a[n]-a[1])+abs(a[1]-a[n-1])+abs(a[n-1]-a[2])+abs(a[2]-a[n]) << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T=1;
cin >> T;
while(T--)
solve();
}
B. Yet Another Coin Problem
题面:
你有 5 种不同的硬币,每种硬币的价值都等于前 5 个三角形数字中的一个:1 、3 、6 、10 和15 。这些硬币种类非常多。你的目标
找出所需的最少数量的这些硬币,使它们的总价值相加正好是 n。
我们可以证明答案总是存在的。
思路:数据范围很大,不可能说直接预处理一遍,然后直接输出值。很好的就会发现很大很大的数的时候,我们每次-15才是最优的方法。但是到了1-30的区间的时候,并不能这么做,例如23=17+6+1+1一共四次,但是我只要23=10+10+3一共三次就可以了。
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
const int N=1e6+10;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
#define int long long
int a[100];
void solve()
{
int n; cin >> n;
int ans=n;
ans=min(ans,n/15+a[n%15]);
ans=min(ans,n/10+a[n%10]);
ans=min(ans,n/6+a[n%6]);
ans=min(ans,n/3+a[n%3]);
int k=(n-15)/15*15;
int m=n-k;
ans=min(ans,k/15+a[m]);
cout << ans << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
for(int i=1;i<=30;i++) a[i]=100;
a[1]=1; a[3]=1; a[6]=1;
a[10]=1; a[15]=1;
for(int i=1;i<=30;i++)
{
if(i>1)
a[i]=min(a[i],a[i-1]+1);
if(i>3)
a[i]=min(a[i],a[i-3]+1);
if(i>6)
a[i]=min(a[i],a[i-6]+1);
if(i>10)
a[i]=min(a[i],a[i-10]+1);
}
int T=1;
cin >> T;
while(T--)
solve();
}
C. Find a Mine
这是一个互动问题。
给你一个行数为 n 列数为 m 的网格。坐标 (x,y) 代表网格上的单元格,其中 x( 1 ≤ x ≤ n 1≤x≤n 1≤x≤n) 是从上往下数的行号,y( 1 ≤ y ≤ m 1≤y≤m 1≤y≤m) 是从左往右数的列号。( 1 ≤ y ≤ m 1≤y≤m 1≤y≤m)是从左数起的列数。网格中保证有 2 颗地雷位于 两个不同的 单元,分别表示为 (x1,y1) 和 (x2,y2)。允许向交互器提出的查询次数不超过 4 次,在这些查询之后,您需要提供其中 一个地雷 的位置。
在每次查询中,您可以选择任意网格单元 (x,y),作为回报,您将得到从两个地雷到所选单元的最小曼哈顿距离,即您将得到值
m
i
n
(
∣
x
−
x
1
∣
+
∣
y
−
y
1
∣
,
∣
x
−
x
2
∣
+
∣
y
−
y
2
∣
)
min(|x−x1|+|y−y1|,|x−x2|+|y−y2|)
min(∣x−x1∣+∣y−y1∣,∣x−x2∣+∣y−y2∣)
您的任务是在进行查询后确定其中一个地雷的位置。
思路:
你可以直接问三个顶点,然后得到一个三个值,问(1,1)、(1,m)、(n,1),然后你根据(1,1)、(1,m)和1,1)、(n,1)这两个组合找到两个点,这两个点必有一个点是雷,你算出来一个点后,直接问一个是不是这个点,如果得到的值是0,那么就是这个点,直接输出就好了,否则就是另外一个点。
当然求点的代码,我就不说了,这个要是不会,真的得加训了。
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
const int N=1e6+10;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
#define int long long
void solve()
{
int a[10]; memset(a,0,sizeof(a));
int n,m; cin >> n >> m;
cout << "? 1 1" << endl; fflush(stdout);
cin >> a[1];
cout << "? " << n << " " << 1 << endl; fflush(stdout);
cin >> a[2];
cout << "? 1 " << m << endl; fflush(stdout);
cin >> a[3];
int k1=a[1]+a[2];
if(k1>=n-1&&(k1-(n-1))%2==0)
{
int j=(k1-(n-1))/2;
int i=a[1]-j;
cout << "? " << i+1 << " " << j+1 << endl;
fflush(stdout);
int x; cin >> x;
if(x==0)
{
cout << "! " << i+1 << " " << j+1 << endl;
fflush(stdout);
return ;
}
}
int k2=a[1]+a[3];
if(k2>=m-1&&(k2-(m-1))%2==0)
{
int j=(k2-(m-1))/2;
int i=a[1]-j;
cout << "! " << j+1 << " " << i+1 << endl;
fflush(stdout);
return ;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T=1;
cin >> T;
while(T--)
solve();
}