C:https://codeforces.com/contest/1150/problem/C
题意:给你n个1或者2,你可以任意排序,要求排好序后的序列的所有前缀和中,含有的素数最多。
比赛时思路:先打个素数表,然后记录保存每一个的素数,每次算出目前前缀和与下一个素数之间的差值,对于这个差值,如果剩下的1和2都加起来都填不了这个 差值,就可以跳出循环。如果可以填补这个差值,再分奇偶进行讨论,如果是奇数:判断是否含有1,如果没1了,那么就跳过这个素数,求出下一个素数与当前前缀和的差值。在填补差值时,优先用2来填充,2用完了再用1来填充。
代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
#define random(a,b) a+rand()%(b-a+1)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 4e5 + 50;
const int INFint = 0xffffff;
const ll INFll = (ll)1e18;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
inline int readint(){
int sgn = 1; int sum = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
if(ch == '-') sgn = -sgn;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
sum = sum*10+(ch-'0');
ch = getchar();
}
return sgn*sum;
}
inline ll readll(){
ll sgn = 1; ll sum = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
if(ch == '-') sgn = -sgn;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
sum = sum*10+(ch-'0');
ch = getchar();
}
return sgn*sum;
}
int n;
vector<int> prime;
bool notprime[maxn];
int arr[maxn];
int cnt1, cnt2;
int sum = 0;
vector<int> ans;
void init(){
memset(notprime, false, sizeof(notprime));
notprime[0] = notprime[1] = true;
for(int i = 2; i < maxn; i++)
if(!notprime[i]){
if(i > maxn / i)continue;//防止后面i*i溢出 (或者i,j用long
//直接从i*i开始就可以,小于i倍的已经筛选过了,注意是j+=i
for(int j = i * i; j < maxn; j += i)
notprime[j] = true;
}
for(int i = 0; i < maxn; ++i)
if(!notprime[i])
prime.push_back(i);
}
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
init();
n = readint();
cnt1 = 0; cnt2 = 0;
for(int i = 0; i < n; ++i){
arr[i] = readint();
if(arr[i] == 1)
cnt1++;
else if(arr[i] == 2)
cnt2++;
}
int Index = 0;
sum = 0;
int now = prime[Index++];
while(cnt1 != 0 || cnt2 != 0){
int dis = now - sum;
if(dis%2){
if(cnt2*2 + cnt1 < dis) break;
if(cnt1 <= 0){
now = prime[Index++];
continue;
}
int need = dis/2;
if(cnt2 >= need){
for(int i = 0; i < need; ++i)
ans.push_back(2);
cnt2 -= need;
ans.push_back(1);
cnt1 -= 1;
}else{
for(int i = 0; i < cnt2; ++i)
ans.push_back(2);
for(int i = 0; i < (dis - cnt2*2); ++i)
ans.push_back(1);
cnt1 -= (dis - cnt2*2);
cnt2 = 0;
}
}else{
if(cnt2*2 + cnt1 < dis) break;
int need = dis/2;
if(need <= cnt2){
for(int i = 0; i < need; ++i)
ans.push_back(2);
cnt2 -= need;
}else if(cnt2*2 + cnt1 >= dis){
for(int i = 0; i < cnt2; ++i)
ans.push_back(2);
for(int i = 0; i < (dis - cnt2*2); ++i)
ans.push_back(1);
cnt1 -= (dis - cnt2*2);
cnt2 = 0;
}else{
break;
}
}
sum = now;
now = prime[Index++];
}
for(int i = 0; i < cnt1; ++i)
ans.push_back(1);
for(int i = 0; i < cnt2; ++i)
ans.push_back(2);
int Size = ans.size();
for(int i = 0; i < Size; ++i)
cout << ans[i] << ' ';
return 0;
}
赛后看大佬的思路:首先,你要知道:除了2和3之间的差值为1(是一个奇数)之外,其他任何两个素数之间的差值一定是一个偶数!!!!(因为,除了2之外,素数都是奇数)。那么这题就很easy了啊!既然后面的差值都是偶数,那么贪心就完事了:优先用2填充,2用完了再用1。当然,对于前面的2和3,在前面先用2和1就行。
代码:
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define Fin freopen("in.txt","r",stdin)
#define Fout freopen("out.txt","w",stdout)
#define Case(T) int T;for(scanf("%d",&T);T--;)
#define fo(i,a,b) for(int i = a; i < b; ++i)
#define fd(i,a,b) for(int i = a; i >= b; --i)
#define me(a,b) memset(a,b,sizeof(a))
#define fi(a,n,val) fill(a,a+n,val)
#define Scand(n) scanf("%d",&n)
#define Scand2(a,b) scanf("%d%d",&a,&b)
#define Scand3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define Scand4(a,b,c,d) scanf("%d%d%d%d",&a,&b,&c,&d)
#define Scans(s) scanf("%s",s)
#define random(a,b) a+rand()%(b-a+1)
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b ? gcd(b,a%b): a; }
const int maxn = 2e5 + 50;
const int INFint = 0xffffff;
const ll INFll = (ll)1e18;
#ifndef ONLINE_JUDGE
#endif // ONLINE_JUDGE
inline int readint(){
int sgn = 1; int sum = 0;
char ch = getchar();
while(!('0' <= ch && ch <= '9')){
if(ch == '-') sgn = -sgn;
ch = getchar();
}
while('0' <= ch && ch <= '9'){
sum = sum * 10 + (ch - '0');
ch = getchar();
}
return sgn * sum;
}
inline ll readll(){
ll sgn = 1; ll sum = 0;
char ch = getchar();
while (ch < '0' || ch > '9') {
if(ch == '-') sgn = -sgn;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
sum = sum*10+(ch-'0');
ch = getchar();
}
return sgn*sum;
}
int n;
int arr[maxn];
int cnt1, cnt2;
int main()
{
#ifndef ONLINE_JUDGE
//Fin;
#endif // ONLINE_JUDGE
cnt1 = cnt2 = 0;
n = readint();
for(int i = 0; i < n; ++i){
arr[i] = readint();
if(arr[i]%2)
cnt1++;
else
cnt2++;
}
if(cnt2){
cout << 2;
cnt2--;
}
if(cnt1){
cout << ' ' << 1;
cnt1--;
}
while(cnt2){
cout << ' ' << 2;
cnt2--;
}
while(cnt1){
cout << ' ' << 1;
cnt1--;
}
return 0;
}