Tokio Marine & Nichido Fire Insurance Programming Contest 2021 (AtCoder Regular Contest 122)

(sf B-Insurance)

题目

传送门

解法

感觉自己的做法还蛮特别的,就来写一写。虽然并不优。

首先将算式转化成:

[sum_{i=1}^n A_i+minleft { sum_{i=1}^n max{x-A_i,-x} ight } ]

我们发现,后面 (max) 的取值和 (2x)(A_i) 的关系有关,于是我们排个序枚举分界点,这样前一半是 (x-A_i) 后一半是 (-x) 就可以快速计算了。

最后再判断一下取 (A_{i}/2)(A_{i+1}/2) 哪个结果小就行了。

代码

#include <bits/stdc++.h>
using namespace std;

#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y) 
#define debug(...) do {cerr<<__LINE__<<" : ("#__VA_ARGS__<<") = "; Out(__VA_ARGS__); cerr<<flush;} while(0)
template <typename T> void Out(T x) {cerr<<x<<"
";}
template <typename T,typename ...I> void Out(T x,I ...NEXT) {cerr<<x<<", "; Out(NEXT...);}

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}

const int maxn=1e5+5;

int n;
double a[maxn],sum,ans;

int main() {
	n=read(9);
	rep(i,1,n) a[i]=read(9);
	sort(a+1,a+n+1);
	rep(i,1,n+1) {
		double x,tmp=i-1-(n-i+1);
		if(tmp>0) x=a[i-1]/2;
		else x=a[i]/2;
		ans=Min(ans,tmp*x-sum);
		sum+=a[i];
	}
	printf("%.10f
",(ans+sum)/n);
	return 0;
}

(sf C-Calculator)

题目

传送门

解法

手玩就能发现,这其实就是将 (n) 拆分成几个斐波那契数。

可以证明,任意正整数 (n) 可以被拆分成互异的斐波那契数。又因为如果选择了 ( ext{fib}_i, ext{fib}_{i+1}) 肯定就会换成 ( ext{fib}_{i+2}),所以我们不会选择连续的斐波那契数。而数据范围中斐波那契数最多到 (87) 项(( ext{fib}_1= ext{fib}_{2}=1)),所以如果我们都选奇数项就有 (44) 项。不过事实上这个上界达不到,因为 ( ext{fib}_{87}+ ext{fib}_{85}+ ext{fib}_{83}>10^{18})

构造就是边加入 (1),边用 (3,4) 操作拓展斐波那契数列,(3,4) 操作的上界是 (86)

所以总体上界为 (130),足以通过此题。

代码

#include <bits/stdc++.h>
using namespace std;

#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y) 
#define debug(...) do {cerr<<__LINE__<<" : ("#__VA_ARGS__<<") = "; Out(__VA_ARGS__); cerr<<flush;} while(0)
template <typename T> void Out(T x) {cerr<<x<<"
";}
template <typename T,typename ...I> void Out(T x,I ...NEXT) {cerr<<x<<", "; Out(NEXT...);}

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}

typedef long long ll;

ll n,f[100];
int sta[100],tp,ans[200],len,fuck;

void init() {
	f[1]=f[2]=1;
	rep(i,3,90) f[i]=f[i-1]+f[i-2];
}

int main() {
	init();
	n=read(9ll);
	fep(i,90,1) if(n>=f[i]) sta[++tp]=i,n-=f[i];
	fep(i,tp,1)
		if(sta[i]&1) {
			while(fuck<sta[i]-1) {
				if(fuck&1) ans[++len]=4;
				else ans[++len]=3;
				++fuck;
			}
			ans[++len]=1;
		}
		else {
			while(fuck<sta[i]-1) {
				if(fuck&1) ans[++len]=4;
				else ans[++len]=3;
				++fuck;
			}
			ans[++len]=2;
		}
	print(len,'
');
	fep(i,len,1) print(ans[i],'
');
	return 0;
}

(sf E-Increasing LCMs)

题目

传送门

解法

我们考虑 (a_n) 满足的条件:将所有数质因数分解,(a_n) 分解后某质数 (p) 的幂次大于 ([1,n-1]) 中任意一个数 (p) 的幂次。

那我们每次找到可以作为末尾的数,然后从后往前填。

考虑贪心的正确性。首先肯定是越填限制越松的。对于同一状态下都可以填的两个数 (i,j),显然使它们可以作为末尾的质因子互异,所以它们的先后顺序是可以随便定的。

代码

#include <bits/stdc++.h>
using namespace std;

#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y) 
#define debug(...) do {cerr<<__LINE__<<" : ("#__VA_ARGS__<<") = "; Out(__VA_ARGS__); cerr<<flush;} while(0)
template <typename T> void Out(T x) {cerr<<x<<"
";}
template <typename T,typename ...I> void Out(T x,I ...NEXT) {cerr<<x<<", "; Out(NEXT...);}

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}

typedef long long ll;

const int maxn=105;

int n,id[maxn];
ll a[maxn],g[maxn][maxn];

int main() {
	n=read(9);
	rep(i,1,n) a[i]=read(9ll),id[i]=i;
	rep(i,1,n) rep(j,1,n) g[i][j]=gcd(a[i],a[j]);
	fep(i,n,1) {
		bool flag=false;
		rep(j,1,i) {
			ll tmp=1;
			rep(k,1,i) if(j^k) tmp=lcm(tmp,g[id[j]][id[k]]);
			if(tmp^a[id[j]]) {
				rep(k,j,i-1) swap(id[k],id[k+1]);
				flag=true; break;
			}
		}
		if(!flag) return puts("No"),0;
	}
	puts("Yes");
	rep(i,1,n) print(a[id[i]],' '); puts("");
	return 0;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/14887586.html