ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
题目链接:https://codeforces.com/contest/1130
B
贪心,看看下一步在两个中选哪一个
题目:
蛋糕是1,2,3,4...升序排序的。
有两个人叠蛋糕,求路途的最小。
---------------------------------
那么也就是说我们要考虑的是下一步谁走哪个数的问题,当一个人确定走哪个数后,
另一个人也确定了走哪个数。
显然,假设走到了第i个数,无论哪个人走了哪个i,之后的最小路途都是固定的。
也就是说,我们需要考虑的是i-1走到i的过程。
也符合了无后效应。
所以对于每一步选择有:a1,a2指的是两个i-1,b1,b2是两个i
min(dis(a1,b1)+dis(a2,b2), dis(a1,b2)+dis(a2,b1))
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
int a[100005],b[100005],n;
int main(){
cin>>n;
ll x,ans=0;
fo(i,1,2*n){
cin>>x;
if(a[x])b[x]=i;
else a[x]=i;
}
a[0]=b[0]=1;
fo(i,1,n){
ans += min(abs(a[i]-a[i-1])+abs(b[i]-b[i-1]), abs(a[i]-b[i-1])+abs(b[i]-a[i-1]));
}
cout<<ans;
}
B 排序解
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
struct node{
int val,idx;
bool operator<(const node &p)const{
if(val==p.val)return idx<p.idx;
else return val < p.val;
}
}a[200005];
int n;
int main(){
cin>>n;
fo(i,1,2*n){
cin>>a[i].val;
a[i].idx = i;
}
sort(a+1,a+1+2*n);
ll ans = 0;
int last = 1, last2=1;
fo(i,1,2*n){
if(i&1){
ans += abs(a[i].idx - last); // 小的和小的
last = a[i].idx;
}else{
ans += abs(a[i].idx - last2); // 大的和大的
last2 = a[i].idx;
}
}
cout<<ans;
}
C
两块陆地,中间河流,求连起来的最小距离
-------------------------------------
两遍BFS遍历两块陆地,枚举任意点的连接
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=55;
const int dx[] = {0,0,-1,1};
const int dy[] = {-1,1,0,0};
int n;
char a[N][N];
bool v[2][N][N];
vector<pair<int, int> > ANS[2];
void bfs(int s1, int c1, int type){
queue<pair<int, int> >q;
q.push({s1,c1});
while(q.size()){
int x = q.front().first;
int y = q.front().second;
q.pop();
if(v[type][x][y])continue;
v[type][x][y]=1;
fo(i,0,3){
int nowx = x+dx[i];
int nowy = y+dy[i];
if(nowx>=1 && nowx<=n && nowy>=1&&nowy<=n && !v[type][nowx][nowy] && a[nowx][nowy]=='0'){
q.push({nowx,nowy});
}
if(nowx>=1 && nowx<=n && nowy>=1&&nowy<=n && !v[type][nowx][nowy] && a[nowx][nowy]=='1'){
ANS[type].push_back({x,y});
}
}
}
}
int main(){
int s1,c1,s2,c2;
cin>>n>>s1>>c1>>s2>>c2;
getchar();
fo(i,1,n){
scanf("%s",a[i]+1);
}
bfs(s1,c1,0);
bfs(s2,c2,1);
int ans = 999999999;
for(pair<int,int> p1 : ANS[0]){ // 河岸1
for(auto p2 : ANS[1]){ // 河岸2
ans = min(ans, (p1.first-p2.first)*(p1.first-p2.first)+
(p1.second-p2.second)*(p1.second-p2.second));
}
}
if(ans ==999999999) ans=0;
cout<<ans;
return 0;
}
D1 && D2 贪心
题目:
一趟火车从1走到n再到1,走圈
输入a,b表示a站有糖果,要运到b站,a!=b
火车容量无限,但是每次离开一个站只能带走一个糖果
现在输出n行
表示火车从各个站出发,运完所有糖果需要的时间
-------------------------------------------------
假设在第i个站有cnt[i]个糖果,
那么我们需要从i出发,走cnt[i]-1圈,然后回到i
再从i出发运到最后一个站,(因为每次只能带1个糖果)
dist(x,y) 表示从x到y的距离,mi[i]表示i运到其他站的最小的一次花费
那么i运出的最小花费为 cost[i] = dist(起点,i) + (cnt[i]-1)*n + mi[i]
现在要求从各个点出发运完全部糖果的最小花费
因为火车可以无限携带糖果
所以我们再运送花费时间最多的那个站的时候,顺路把其他站要运的也带上运完
ans = max(cost[i])
#include<bits/stdc++.h>
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=5050;
int n,m,cnt[N],mi[N];
int dist(int x, int y){
if(y>=x)return y-x; // >=!
else return n-(x-y);
}
int main(){
scanf("%d%d",&n,&m);
int x,y;
memset(mi, 127, sizeof(mi));
fo(i,1,m){
scanf("%d%d",&x,&y); // x有糖果,要运到y
cnt[x]++;
mi[x] = min(mi[x], dist(x,y));
}
// 因为火车可以放无限的糖果
// 在每一个站可以多带走一个糖果
// 所以在运送最长的那一趟糖果的同时,带上其他趟
fo(i,1,n){ // 起点
ll ans = -1;
fo(j,1,n){ // 枚举每个站
if(cnt[j]==0)continue;
// 每个站的最短运输时间取最大即为该起点i需要的总运输时间
ans = max(ans, (ll)n*(cnt[j]-1) + dist(i,j) + mi[j]);
}
printf("%lld ",ans);
}
return 0;
}
E
求max(sum(R-L+1)*a[i]) 0<=L<=R<n, L<=i<=R
Alice写了个错误的算法,类似 连续最大子段和吧
现在知道正确答案和Alice的答案差k
求数列
-------------------------------------------
假设 a[0] = -1, a[i]>=1,那么sum(a) = S
Alice 的答案为 (n-1)*(S+1) 除了第一个数
可能的答案为 S*n 或Aliice的答案
假设正确答案为 S*n
那么 S*n - (n-1)*(S+1) = k
即 S - n + 1 = k
我们可以令 n = 2000 构造数组
#include<bits/stdc++.h>
using namespace std;
long long k,S,a[2006];
int main(){
// S*n - (n-1)*(S+1) = k
cin>>k; // S - n + 1 = k
long long n = 2000;
S = k+n-1;
a[0] = -1;
for(int i=2;i<n;i++)a[i]=1;
a[1] = S-a[0]-(n-2); //其他都为1
cout<<n<<endl;
int i=2;
// 不超过1e6
while(a[1]>1000000){
a[i++]+=1000000-1;
a[1]-=1000000-1;
}
for(int i=0; i<n; i++){
cout<<a[i]<<" ";
}
return 0;
}