目录
D. Balanced Round
E. Cardboard for Pictures
F. We Were Both Children
G. The Morning Star
H. The Third Letter
题意:有 n 个问题,问题 i 的难度是a[i],进行下面两个操作:
1. 从列表中删除一些问题 (可以是 0 个)
2. 将剩下的问题按任意顺序重新排列。
当且仅当任意两个连续问题的难度绝对值最多相差 k 时,一轮比赛才算平衡,为了使问题的排列平衡,你至少要删除多少个问题?
思路:如何排列可以使得结果最优呢?我们发现:当按照难度进行排序的时间,满足 "任意两个连续问题的难度绝对值最多相差 k " 的最长子段的长度会最大,然后,将其余的问题删除即可。
参考代码:
#include
using i64 = long long;
void solve() {
int n, k;
cin >> n >> k;
vector a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a.begin(), a.end());
int cnt = 1, ans = 1;
for (int i = 1; i < n; i++) {
if (a[i] - a[i - 1] <= k) {
cnt++;
} else {
cnt = 1;
}
ans = max(ans, cnt);
}
cout << n - ans << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
题意:有 n 副成正方形的画,给定每幅画中一正方形阴影部分的边长 s[i] ,每幅画的边长是其中阴影部分的边长加上 2×w ,给你这 n 副画的面积之和 c ,求 w 的值。
思路:显然,答案 w 具有二分性质,为了防止越界,在每次检查答案合法性时,当 sum>c 时,跳出循环即可。
参考代码:
#include
using namespace std;
using ll = long long;
ll a[1100000];
ll check(ll mid,ll n,ll c)
{
ll sum=0;
for(ll i=1;i<=n;i++)
{
sum+=(2*mid+a[i])*(2*mid+a[i]);
if(sum>c) break;
}
return sum;
}
void solve()
{
ll n,c;cin>>n>>c;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
}
ll l=0,r=1e9;
ll mid;
while(l+1!=r)
{
mid=(l+r)>>1;
if(check(mid,n,c)>c) r=mid;
else if(check(mid,n,c)==c)
{
l=mid;
break;
}
else l=mid;
}
cout<>t;
while(t--)
solve();
return 0;
}
题意:在坐标原点有 n 只青蛙,每隔一秒,它们会向同一方向分别跳动 a[i] 的长度,可以任意在坐标 1∼n 中选择一个坐标放上陷阱,问怎样设计陷阱,可以使得跳到陷阱上的青蛙数量最多。
思路:枚举每一个 ≤n 的 a[i] 的倍数即可。
参考代码:
#include
using namespace std;
#define int long long
int t,n,a[200010],dp[200010],ans=0;
//dp只是预处理数组而已,没什么别的含义...
int getans(int x){
int sum=0;
for(int i=1;i*i<=x;i++){
if(x%i==0){
if(i*i==x) sum+=dp[i];
else sum+=dp[i],sum+=dp[x/i];
}
}
return sum;
}
signed main(){
cin>>t;
while(t--){
memset(dp,0,sizeof(dp));
ans=0;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
//预处理
for(int i=1;i<=n;i++) if(a[i]<=n) dp[a[i]]++;
for(int i=1;i<=n;i++) ans=max(ans,getans(i));
cout<
思路:假设同方向的点的个数是 x,那么罗盘有 x 个可以选择的点,晨星有 x−1 个可以选择的点,即该方向对答案的贡献为 x*(x−1) ,我们统计四个方向分别有多少点,把其贡献累加起来即可。
参考代码:
#include
using namespace std;
using ll = long long;
const ll ma = 200005;
mapmp[4];
void solve()
{
for (int i = 0; i < 4; ++i)
mp[i].clear();
int n;
scanf("%d", &n);
ll ans = 0;
for (int i = 1; i <= n; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
ans += mp[0][x]++;
ans += mp[1][y]++;
ans += mp[2][x - y]++;
ans += mp[3][x + y]++;
}
printf("%lld\n", 2 * ans);
}
int main()
{
ll t;cin>>t;
while(t--) solve();
}
题意:为了赢得最艰苦的战斗,米尔恰为他的军队想出了一个好策略。他有 n个士兵,并决定以某种方式将他们安排在营地里。每个士兵都必须属于一个营地,在 x 轴上的每个整数点都有一个营地。该策略由 m个限制条件组成。条件 i 表明士兵u 与士兵 v 距离 w , w 可正可负,即具有方向性。现在,米尔恰想知道是否存在满足所有条件的士兵分区方案。
思路:考察了带权并查集模板。
参考代码: