考前欢乐赛
A. 炒币
可以贪心峰入谷出
也可以 , 取 记录前驱
但是因为数太大了,精度会炸
取 降低误差 ,然后就切了》
为啥取 能够降低误差? 与原数不是一一对应吗? 不是科学计数法吗?
上午炸完的我如是问到。。。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; bool f = 0; char c = getchar();
while(!isdigit(c)){f = c == '-'; c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 200005;
double f[maxn];
int n, a[maxn], pre[maxn], p[maxn];
int main(){
freopen("coin.in","r",stdin);
freopen("coin.out","w",stdout);
n = read();
for(int i = 1; i <= n; ++i)a[i] = read();
f[0] = log(1); int pos = 0;
for(int i = 1; i <= n; ++i){
f[i] = f[i - 1]; pre[i] = -1;
if(f[pos] + log(a[pos]) > f[i] + log(a[i])){
f[i] = f[pos] + log(a[pos]) - log(a[i]);
pre[i] = pos;
}else pos = i;
}
for(int i = n; i >= 1; ){
if(pre[i] == -1){--i;continue;}
p[i] ^= 1; p[pre[i]] ^= 1; i = pre[i];
}
for(int i = 1; i <= n; ++i)printf("%d ",p[i]);
return 0;
}
B. 凑数
考场写错了 挂惨了
注意到 的价值取全由 凑出最小的花费
那么如果 单个凑够一个 可以转化为花费最小的方案,于是可以把 缩小到 范围内,此时 中较大数是 的,于是可以枚举
题解做法考虑按照价值排序,假设优先级
那么 不会选超过 个 不会选超过 个,这两个有一个小于等于 可以枚举
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ll read(){
ll x = 0; bool f = 0; char c = getchar();
while(!isdigit(c)){f = c == '-'; c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 200005;
ll n, a, b, x, y, z;
void sol(){
n = read(), a = read(), b = read();
x = read(), y = read(), z = read();
if(x * a <= y && x * b <= z){
printf("%lld\n",n * x);
return;
}
if(a * z < b * y)swap(a, b), swap(y, z);
ll mxa = n / a, mxb = a;
if(mxa > mxb){
swap(mxa, mxb);
swap(a, b);
swap(y, z);
}
ll ans = n * x;
for(int i = 0; i <= mxa; ++i){
ll res = n - i * a; if(res < 0)break;
ll k = min(res * x, res / b * z + (res % b) * x);
ans = min(ans, k + i * y);
}
printf("%lld\n",ans);
}
int main(){
freopen("cs.in","r",stdin);
freopen("cs.out","w",stdout);
int t = read();
for(int i = 1; i <= t; ++i)sol();
return 0;
}
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ll read(){
ll x = 0; bool f = 0; char c = getchar();
while(!isdigit(c)){f = c == '-'; c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 200005;
ll n, a, b, x, y, z;
void sol(){
n = read(), a = read(), b = read();
x = read(), y = read(), z = read();
ll gcd = __gcd(a, b);
ll lcm = a / gcd * b, ans = n * x;
ll aa = lcm / a, bb = lcm / b;
ll res = n, base = 0;
if(lcm <= n){
ll cos = min(aa * y, bb * z);
cos = min(cos, lcm * x);
res = (n % lcm) + lcm;
base = (n / lcm - 1) * cos;
}
if(a < b){
swap(a, b);
swap(aa, bb);
swap(y, z);
}
for(ll i = 0; i <= aa; ++i){
if(i * a > res)break;
ll k = res - i * a;
ll p = min(k / b * z + (k % b) * x, k * x);
ans = min(ans, p + i * y + base);
}
printf("%lld\n",ans);
}
int main(){
// freopen("cs.in","r",stdin);
// freopen("cs.out","w",stdout);
int t = read();
for(int i = 1; i <= t; ++i)sol();
return 0;
}
C. 同构
应该多打一点表的。。。
发现质因子集合相同的可以随便排列,然后可以处理一下
另外就是 相等的 因子可以互换,即含 因子的数量相同,并且和其他数的互质情况相同,于是也需要乘上阶乘
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; bool f = 0; char c = getchar();
while(!isdigit(c)){f = c == '-'; c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 1000005;
const int mod = 1e9 + 7;
int n, fac[maxn];
int c[maxn], t[maxn];
int prime[maxn], cnt, mi[maxn];
bool flag[maxn];
int main(){
freopen("tg.in","r",stdin);
freopen("tg.out","w",stdout);
n = read();
fac[0] = 1; for(int i = 1; i <= n; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
for(int i = 2; i <= n; ++i){
if(!flag[i])prime[++cnt] = i, mi[i] = i;
for(int j = 1; j <= cnt && prime[j] * i <= n; ++j){
flag[i * prime[j]] = 1;
mi[i * prime[j]] = prime[j];
if(i % prime[j] == 0)break;
}
}
for(int i = 2; i <= n; ++i)if(flag[i]){
int p = 1, j = i;
while(j > 1){
int m = mi[j]; p *= m;
while(j % m == 0) j /= m;
}
++c[p];
}else{
++t[n / i];
++c[i];
}
++t[1];
int ans = 1;
for(int i = 1; i <= n; ++i)ans = 1ll * ans * fac[c[i]] % mod;
for(int i = 1; i <= n; ++i)ans = 1ll * ans * fac[t[i]] % mod;
printf("%d\n",ans);
return 0;
}
D. 重建
发现对于非关键点,一定会连到一个关键点上,而关键点之间可以通过高铁转一圈,于是他们不一定直接相连,于是把关键点合并跑一棵最小生成树,这些边是每个城市必须自己解决的,直接统计贡献即可
然后考虑把图缩成了只有若干关键点,对于一个城市,如果直接连接他的关键点,一定也是用最小生成树上的边,于是对新图跑出最小生成树记录用到的边
结合高铁直接建最小生成树,于是你就有了 分考场暴力。(我还以为有 )
考虑优化后面的过程,模拟最小生成树
我们会按照边权从小到大考虑是否加边
那么对于相邻的两个城市, 较大的城市连的边 较小的城市一定连了
在任意时刻, 小的城市的连通性都是更强的
而且如果考虑高铁的连接之后, 两个图的联通性就完全一致,此时对于 较大的图就没有考虑的必要了
那么我们按照 升序进行考虑,每次处理 之间的高铁,以及其中 较大的连边贡献
具体来讲先对边权排序,每次二分出加入边的数量,用前缀和统计贡献
然后算出剩余的联通块数,连上高铁,对于 较大的城市就可以删去了
注意到因为所有车站需要联通,所以 最小的城市必然完整的建出最小生成树,所以统计上其贡献即可
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; bool f = 0; char c = getchar();
while(!isdigit(c)){f = c == '-'; c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return f ? -x : x;
}
const int maxn = 5000005;
int n, m;
struct edge{
int u, v, w;
friend bool operator < (const edge &x, const edge &y){
return x.w < y.w;
}
}e[maxn * 5];
int l, r, key[100005], a[100005], b[100005];
int f[maxn], nk[100005], rval[maxn];
int fa(int x){return f[x] == x ? x : f[x] = fa(f[x]);}
bool merge(int x, int y){x = fa(x); y = fa(y); if(x == y)return false; f[y] = x; return true;}
bool vis[maxn];
ll sb, sum[maxn];
int p[maxn];
bool cmp(int x, int y){return a[x] < a[y];}
int main(){
#define int long long
freopen("rb.in","r",stdin);
freopen("rb.out","w",stdout);
n = read(), m = read();
for(int i = 1; i <= m; ++i){
int u = read() + 1, v = read() + 1, w = read();
e[i] = {u, v, w};
}
sort(e + 1, e + m + 1);
l = read(); for(int i = 1; i <= l; ++i)a[i] = read(), b[i] = read(), sb += b[i];
r = read(); for(int i = 1; i <= r; ++i)key[i] = read() + 1;
ll cost = 0; int count = 0;
for(int i = 1; i <= n; ++i)f[i] = i;
for(int i = 1; i <= r; ++i)merge(key[1], key[i]);
for(int i = 1; i <= m; ++i)if(merge(e[i].u, e[i].v))cost += e[i].w, vis[i] = true, ++count;
cost = cost * l + sb * count;
for(int i = 1; i <= n; ++i)f[i] = i;
for(int i = 1; i <= m; ++i)if(vis[i])merge(e[i].u, e[i].v);
for(int i = 1; i <= r; ++i)nk[fa(key[i])] = i;
for(int i = 1; i <= n; ++i)nk[i] = nk[fa(i)];
for(int i = 1; i <= n; ++i)f[i] = i;
int cnt = 0;
for(int i = 1; i <= m; ++i){
int u = nk[e[i].u], v = nk[e[i].v];
if(merge(u, v))rval[++cnt] = e[i].w;
}
for(int i = 1; i <= cnt; ++i)sum[i] = sum[i - 1] + rval[i];
for(int i = 1; i <= l; ++i)p[i] = i;
sort(p + 1, p + l + 1, cmp);
for(int i = 1; i <= l; ++i)f[i] = i;
for(int i = 1; i < l; ++i){
int u = p[i], v = u % l + 1;
u = fa(u); v = fa(v);
if(b[u] < b[v])swap(u, v);
int k = upper_bound(rval + 1, rval + r, a[p[i]] - b[u]) - rval - 1;
cost += 1ll * b[u] * k + sum[k] + 1ll * a[p[i]] * (r - k);
f[u] = v;
}
cost += 1ll * b[fa(1)] * (r - 1) + sum[r - 1];
printf("%lld\n",cost);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】