D. Bouncing Boomerangs
题目大意:构造障碍物摆放,使得符合 从 i 列的底部向上投掷反弹次数要求。
题目思路:
首先,我们可以想到,如果第i列只有一次反弹,那么就意味着以后不会再碰到反弹物。
其次就是尽可能重用之前放的物体。
- 如果第 i 列有两次反弹,那么这个随后肯定需要一个只有一次反弹的点。我们记作 2 -> 1
- 如果第 i 列有三次反弹,那么这个第三次反弹。那么这个可以重用随后的一次 / 二次 / 三次反弹的点。 记作3->3 或3->2或3->1
综上我们得出,3->3 , 3->2 , 3->1 , 2 ->1 其中我们发现,1同时被2,3需要,所以我们碰到3次反弹的时候,优先分配给他随后的2,3次反弹点来重用。
明显要倒着来遍历,并且下标偏后边的位置尽量低一点,留给之前的多次反弹用。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN = 3e5+5;
const ll mod = 1e9+7;
int a[MAXN];
struct node
{
int x,y;
node(){}
node(int a,int b){
x = a;y = b;
}
};
vector<node>ans;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
int k = n;
vector<node>one,two,three,four;
bool f = 1;
for(int i=n;i>=1;i--){
if(a[i] == 1){
one.push_back(node(i,k));
ans.push_back(node(k--,i));
}
if(a[i] == 2){
if(one.size()!=0){
node idx = one[one.size()-1];
one.pop_back();
int hang = idx.y;
ans.push_back(node(hang,i));
two.push_back(node(i,hang));
}
else f = 0;
}
if(a[i] == 3){
//cout<<i<<" + "<<k<<endl;
if(three.size() != 0){
node idx = three[three.size()-1];
three.pop_back();
int lie = idx.x;
//cout<<lie<<" + "<<idx.y<<endl;
three.push_back(node(i,k));
ans.push_back(node(k,lie));
ans.push_back(node(k--,i));
}
else if(two.size() != 0){
three.push_back(node(i,k));
node idx = two[two.size()-1];
two.pop_back();
int lie = idx.x;
ans.push_back(node(k,lie));
ans.push_back(node(k--,i));
}
else if(one.size() != 0){
three.push_back(node(i,k));
node idx = one[one.size()-1];
one.pop_back();
int lie = idx.x;
ans.push_back(node(k,lie));
ans.push_back(node(k--,i));
}
else f = 0;
}
}
if(!f){
cout<<-1<<endl;
}
else{
cout<<ans.size()<<endl;
for(auto to:ans){
cout<<to.x<<" "<<to.y<<endl;
}
}
}
E. Carrots for Rabbits
题目大意:
n根胡萝卜,分成k段,每段的平方和最小是多少。
题目思路:
首先想到的可能就是优先分大的,并且尽量均分,有一个很容易想到的错误做法就是,一个优先队列,每次取个最大的,然后分成两半塞回去。
考虑10分为三段,以上思路是2,3,5。但是正确的应该是均分3,3,4。
这时候思路就很明显了,每次我们必须对某一根萝卜均分,均分成当前k段,和均分成k+1段,之间的差距越大,我们就越应该分他。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN = 3e5+5;
const ll mod = 1e9+7;
ll b[MAXN],a[MAXN];
ll get(ll x,ll k){
if(a[x] < k)return 1e9;
ll duan = a[x]/k;
ll num = a[x]%k;
return num*(duan+1)*(duan+1) + (k-num)*(duan)*(duan);
}
struct node
{
ll x,y;
node(){}
node(ll a,ll b){
x = a,y = b;
}
bool operator < (const node & r)const{
return y<r.y;
}
};
int main()
{
ll n,k;
cin>>n>>k;
priority_queue<node>q;
for(ll i=1;i<=n;i++){
cin>>a[i];b[i] = 1;
q.push(node(i , get(i,1) - get(i,2)));
}
ll num = k-n;
//cout<<"----"<<endl;
while(num--){
node x = q.top();
q.pop();
++b[x.x];
ll now = get(x.x,b[x.x]) - get(x.x,b[x.x]+1);
q.push(node(x.x , now ));
}
ll ans = 0;
// cout<<b[1]<<endl;
for(ll i=1;i<=n;i++){
ans += get(i,b[i]);
}
cout<<ans<<endl;
}