The 3rd Universal Cup. Stage 40: Potyczki F 个人题解
记录一个关于 fib 的构造。
如果能把序列变为全 1,那么我们只需要最后回滚一遍就解决了此题。
只对两个数操作比较难,考虑对相邻的三个数操作。为了进一步简化,我们设前两个数为 1。
利用加法可以让第二个数变为 fib 的偶数项,我们猜测利用 fib 去构造数和二进制差不了太多。
通过打表发现,30000 内的数最多需要 14 个 fib 偶数项组成,于是把第三个数变成 1 最多 42 次操作。
于是总操作数为 \(n+n+42n=44n\approx 1,320,000\),实现时会有一些常数级别的误差。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double dou;
typedef pair<int,int> pii;
#define fi first
#define se second
#define mapa make_pair
typedef long double ld;
typedef unsigned long long ull;
#define ep emplace_back
template <typename T>inline void read(T &x){
x=0;char c=getchar();bool f=0;
for(;c<'0'||c>'9';c=getchar()) f|=(c=='-');
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
x=(f?-x:x);
}
const int N=1e6+5;
int n;
int a[N];
int f[25];
char s[2]={'-', '+'};
struct node{
int x, op, y;
};
vector<node> vec;
void perform(int x, int op, int y){
assert(abs(x-y)==1);
vec.push_back((node){x, op, y});
if(op==0){
a[x]-=a[y];
}
else{
a[x]+=a[y];
}
}
int main(){
// freopen("D:\\nya\\acm\\A\\test.in","r",stdin);
// freopen("D:\\nya\\acm\\A\\test.out","w",stdout);
read(n);
for(int i=1; i<=n; ++i) read(a[i]);
f[0]=1; f[1]=1;
for(int i=2; i<=24; ++i) f[i]=f[i-1]+f[i-2];
a[0]=n+1; a[n+1]=n+1;
int pos=0;
for(int i=1; i<=n; ++i){
if(a[i]!=1) continue;
int x=i-1;
if(a[i+1]<a[i-1]) x=i+1;
while(a[x]!=1) perform(x, 0, i);
if(x<i) pos=x;
else pos=i;
}
for(int i=pos+2; i<=n; ++i){
int cur=0;
while(f[cur+2]<a[i]) {
if(cur==0){
perform(i-1, 1, i-2);
}
else{
perform(i-2, 1, i-1);
perform(i-1, 1, i-2);
}
cur+=2;
}
while(a[i]!=1){
if(f[cur]<a[i]){
perform(i, 0, i-1);
}
else{
perform(i-1, 0, i-2);
cur-=2;
if(cur!=0) perform(i-2, 0, i-1);
}
}
while(a[i-1]!=1||a[i-2]!=1){
if(a[i-2]>a[i-1]) perform(i-2, 0, i-1);
else perform(i-1, 0, i-2);
}
}
for(int i=pos-1; i>=1; --i){
int cur=0;
while(f[cur+2]<a[i]) {
if(cur==0){
perform(i+1, 1, i+2);
}
else{
perform(i+2, 1, i+1);
perform(i+1, 1, i+2);
}
cur+=2;
}
while(a[i]!=1){
if(f[cur]<a[i]){
perform(i, 0, i+1);
}
else{
perform(i+1, 0, i+2);
cur-=2;
if(cur!=0) perform(i+2, 0, i+1);
}
}
while(a[i+1]!=1||a[i+2]!=1){
if(a[i+2]>a[i+1]) perform(i+2, 0, i+1);
else perform(i+1, 0, i+2);
}
}
for(int i=2; i<=n; ++i) perform(i, 1, i-1);
// for(int i=1; i<=n; ++i) cout<<a[i]<<' '; cout<<endl;
printf("%d\n", (int)vec.size());
for(auto t:vec){
printf("%d %c %d\n", t.x, s[t.op], t.y);
}
return 0;
}