记录44
#include<bits/stdc++.h>
using namespace std;
long long f(long long a,long long b){
long long t=a-b;
return abs(t);
}
int main(){
long long a[100010]={},n,m,s1,s2,p;
long long b[100010]={};
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>m>>p>>s1>>s2;
a[p]+=s1;
long long D=0,T=0;
for(int i=1;i<=n;i++){
if(i<=m) D+=a[i]*(m-i);
else T+=a[i]*(i-m);
}
if(D==T){
cout<<m;
return 0;
}
for(int i=1;i<=n;i++){
long long Dn=D,Tn=T;
if(i<m) Dn+=s2*(m-i);
if(i>m) Tn+=s2*(i-m);
long long t=f(Dn,Tn);
b[i]=t;
}
long long x=b[1],num=1;
for(int i=2;i<=n;i++){
if(x>b[i]){
x=b[i];
num=i;
}
}
cout<<num;
return 0;
}
题目传送门
https://www.luogu.com.cn/problem/P5016
突破点
一个兵营的气势为:该兵营中的工兵数× 该兵营到 m 号兵营的距离;参与游戏 一方的势力定义为:属于这一方所有兵营的气势之和
游戏过程中,某一刻天降神兵,共有 s1 位工兵突然出现在了 p1 号兵营。作为轩轩和凯凯的朋友,你知道如果龙虎双方气势差距太悬殊,轩轩和凯凯就不愿意继续玩下去了。为了让游戏继续,你需要选择一个兵营 p2,并将你手里的 s2 位工兵全部派往 兵营 p2,使得双方气势差距尽可能小。
👉维护游戏平衡,双方兵数*距离差不多
思路
- 写一个绝对值函数计算双方差距
- 用数组记录一下初始的情况
- 更新突然出现的兵,更新数组值
- 遍历手头的兵调往不同兵营后出现的差距(绝对值)情况
- 遍历所有差距,找到最小的情况
代码简析
#include<bits/stdc++.h>
using namespace std;
long long f(long long a,long long b){
long long t=a-b;
return abs(t);
}
int main(){
long long a[100010]={},n,m,s1,s2,p;
long long b[100010]={};
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>m>>p>>s1>>s2;
a[p]+=s1;
long long D=0,T=0;
for(int i=1;i<=n;i++){
if(i<=m) D+=a[i]*(m-i);
else T+=a[i]*(i-m);
}
...
return 0;
}
f 函数 👉 计算差距,因为差距是双方累加起来的数相减,所以要用long long
依次输入兵营情况
a[p]+=s1; 👉 p兵营突然多出的兵
long long D=0,T=0; 👉 累计求双方的气势总和
#include<bits/stdc++.h>
using namespace std;
long long f(long long a,long long b){
long long t=a-b;
return abs(t);
}
int main(){
long long a[100010]={},n,m,s1,s2,p;
long long b[100010]={};
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
cin>>m>>p>>s1>>s2;
a[p]+=s1;
long long D=0,T=0;
for(int i=1;i<=n;i++){
if(i<=m) D+=a[i]*(m-i);
else T+=a[i]*(i-m);
}
if(D==T){
cout<<m;
return 0;
}
for(int i=1;i<=n;i++){
long long Dn=D,Tn=T;
if(i<m) Dn+=s2*(m-i);
if(i>m) Tn+=s2*(i-m);
long long t=f(Dn,Tn);
b[i]=t;
}
long long x=b[1],num=1;
for(int i=2;i<=n;i++){
if(x>b[i]){
x=b[i];
num=i;
}
}
cout<<num;
return 0;
}
if(D==T){} 👉 双方气势相等,往分界线的中立兵营派兵
for循环 👉 从头到尾遍历兵营依次派兵,看看情况
long long Dn=D,Tn=T; 👉 后面用来更新龙虎双方的气势总和
用新加入的兵直接×距离,然后加入总气势就可以了
long long t=f(Dn,Tn); 👉 t数组用来存气势的差值
b[i]=t; 👉 差值存进b数组
long long x=b[1],num=1; 👉 x存最小气势,从第一个开始向后比较,num存下标编号
循环找出最小龙虎气势之差
补充
"十年OI一场空,不开long long见祖宗"这句信奥圈的"黑话"道出了无数选手的血泪史:
1. 字面含义:十年努力一朝归零
"十年OI一场空":辛苦训练多年,因一个小失误全盘皆输
"不开longlong见祖宗":变量类型没开
long long,导致答案错误,只能"去见祖宗"(回家种田)核心本质:
int与long long的范围差异,是竞赛中最隐蔽、最致命的陷阱。
2. 数据范围对比:为什么必须用long long
类型 占用空间 范围 超出后果 int4字节 -2³¹ ~ 2³¹-1
约 -21亿 ~ +21亿溢出后变为负数,答案全错 long long8字节 -2⁶³ ~ 2⁶³-1
约 -9×10¹⁸ ~ +9×10¹⁸几乎不会溢出 CSP-J典型数据:
n ≤ 10⁵,a[i] ≤ 10⁹,累加和可达10¹⁴,远超int上限。
3. 四大翻车场景(真实血泪)
场景1:累加求和(最常见)
int sum = 0; // ❌ 错误:int存不下 for (int i = 0; i < n; i++) { sum += a[i]; // a[i]最大1e9, n=1e5时,sum可达1e14,int溢出变成负数 } cout << sum; // 输出负值,0分!正确:
long long sum = 0; // ✅ 正确:开long long场景2:乘法运算(最隐蔽)
int a = 100000, b = 100000; int c = a * b; // ❌ 错误:a*b先int溢出,结果=1410065408(错误) // 正确: long long c = 1LL * a * b;场景3:函数返回值(最崩溃)
int factorial(int n) { // ❌ 错误:返回类型int if (n == 0) return 1; return n * factorial(n - 1); // n=20就溢出,结果错误 }正确:
long long factorial(int n) { // ✅ 正确:返回long long if (n == 0) return 1; return n * factorial(n - 1); }场景4:DP状态值(最致命)
int dp[1000][1000]; // ❌ 错误:DP值可能爆int dp[i][j] = dp[i-1][j] + dp[i][j-1]; // 组合数问题,值增长极快正确:
long long dp[1000][1000]; // ✅ 正确:状态值开long long
4. 为什么难调试?隐蔽性分析
阶段 表现 选手心理 编译期 无错误,无警告 "代码没问题,稳了" 样例测试 样例小,int够用,输出正确 "AC了,交卷" 评测时 大数据int溢出,输出负数/异常值 "WA了?不可能!我代码逻辑完美" 赛后 发现是int溢出,欲哭无泪 "十年OI一场空..." 致命点:小数据无法暴露问题,大数据一击必杀,且溢出后结果不可预测,调试困难。
5. 正确做法:竞赛安全编码规范
原则1:凡求和、累乘、DP值,无脑开long long
// 看到题目数据范围有1e9,直接开long long long long sum = 0; // 求和 long long prod = 1; // 累乘 long long dp[1005] = {0}; // DP数组原则2:强制转换习惯
int a, b; // 乘法前先转long long long long c = 1LL * a * b; // 1LL * a先转long long,再乘b // 或者在定义时转 long long c = static_cast<long long>(a) * b;原则3:函数返回值和参数
// 任何可能计算大数的函数,返回类型用long long long long calc(int n) { long long res = 0; // ... return res; } // 参数也可以用long long,避免传入int溢出 void func(long long x) { ... }原则4:数组大小计算
int n; cin >> n; // 如果n最大1e5,且数组存的是累加值,开long long vector<long long> a(n + 1);
6. 竞赛场真实案例
2023年CSP-J复赛 第3题:
n ≤ 10⁵,a[i] ≤ 10⁹,求和。
int选手:sum开出
int,60%数据通过,40%大数据WA,总分60分。long long选手:sum开
long long,100分。2022年某省赛:组合数模运算,未开long long的选手全军覆没。
7. 这句话的幽默性与警示性
幽默:用夸张的"见祖宗"形容回家种田,戏谑中带着自嘲
警示:用最直白的方式告诫后人——细节决定成败
传承:老选手用血泪总结的教训,新选手听到就刻进DNA
现代版本:
"十年OI一场空,不开long long见祖宗,加速cin两行泪,忘记freopen两行泪"
8. 终极解决方案:无脑模板
#include <bits/stdc++.h> using namespace std; // 看到题目,先写这三行: ios::sync_with_stdio(false); cin.tie(nullptr); // 然后定义变量: int n; // 下标用int long long ans = 0; // 答案一律long long vector<long long> a(n + 1); // 数据数组一律long long // 计算时: for (int i = 1; i <= n; i++) { ans += 1LL * a[i - 1] * a[i]; // 乘法先转long long } cout << ans << endl; // 输出long long
9. 一句话总结
在CSP-J中,当你犹豫"这个变量要不要开long long"时,答案永远是:开!
因为开大了只是浪费8字节内存(可忽略),开小了这个变量可能让你"见祖宗"。
龙虎斗题解与long long警示
1308

被折叠的 条评论
为什么被折叠?



