傳送門
文章目錄
題意:
給你nnn個數,每次操作可以選擇將某個數+1,?1+1,-1+1,?1,求最少進行多少次操作使得所有數都為正數且gcd>1gcd>1gcd>1。
思路:
考慮gcd=2gcd=2gcd=2的情況,即將所有數變成偶數,這樣的操作最多有nnn次。
再考慮證明一個結論:操作數量≥2\ge2≥2的數不超過n2\frac{n}{2}2n?。
利用反證法,如果超過n2\frac{n}{2}2n?,那么總的操作數>n2?2=n>\frac{n}{2}*2=n>2n??2=n,與上面結論不符合,不成立。
所以對于一個數,這個數至少有12\frac{1}{2}21?的概率被最多操作一次,那么一個隨機算法就來啦,從序列中隨機選出來kkk個數,將ai,ai+1,ai?1a_i,a_i+1,a_i-1ai?,ai?+1,ai??1分解質因子,對于每個因子計算答案,正確率為1?12k1-\frac{1}{2^k}1?2k1?,kkk足夠大的時候很難出錯,可是我臉黑雅痞,k=50k=50k=50都能wawawa,試了各種,不是TTT就是wawawa的,不得不說臉是真滴黑,randomshufflerandom\ \ shufflerandom??shuffle三遍才過。
update:update:update: 知道為什么TTT了,我存質因子用的vectorvectorvector,最后還需要排序去重,改成mapmapmap就快多了。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
;
map
<LL
,int>diver
;
LL a
[N
];
LL prime
[N
],cnt
;
bool st
[N
];void get_prime(int n
) {for(int i
=2;i
<=n
;i
++) {if(!st
[i
]) {prime
[++cnt
]=i
;for(int j
=i
+i
;j
<=n
;j
+=i
) st
[j
]=1;}}
}void divide(LL x
) {for(int i
=1;i
<=cnt
&&prime
[i
]<=x
;i
++) {if(x
%prime
[i
]==0) {diver
[prime
[i
]]=1;while(x
%prime
[i
]==0) x
/=prime
[i
];}}if(x
>1) diver
[x
]=1;
}LL
calc(LL x
) {LL now
=0;for(int i
=1;i
<=n
;i
++) {if(x
>a
[i
]) now
+=x
-a
[i
];else now
+=min(a
[i
]%x
,x
-a
[i
]%x
);}return now
;
}int main()
{
get_prime(1e6);scanf("%d",&n
);for(int i
=1;i
<=n
;i
++) scanf("%lld",&a
[i
]);random_shuffle(a
+1,a
+1+n
);random_shuffle(a
+1,a
+1+n
);random_shuffle(a
+1,a
+1+n
);for(int i
=1;i
<=min(100,n
);i
++) {divide(a
[i
]);divide(a
[i
]+1);divide(a
[i
]-1);}LL ans
=n
;for(auto x
:diver
) ans
=min(ans
,calc(x
.first
));printf("%lld\n",ans
);return 0;
}
總結
以上是生活随笔為你收集整理的Ozon Tech Challenge 2020 (Div.1 + Div.2) F. Kuroni and the Punishment 随机化的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。