多测不清空,爆零两行泪。
A - Energy Crystals
题意
有三个整数
a
1
a_1
a1,
a
2
a_2
a2,
a
3
a_3
a3,可以将其中一个数改为任意正整数,但是必须满足对于任意两个
i
i
i,
j
(
1
≤
i
,
j
≤
3
)
j(1\le i,j\le3)
j(1≤i,j≤3),有:
a
i
≥
⌊
a
j
2
⌋
a_i\ge\lfloor\frac{a_j}{2}\rfloor
ai≥⌊2aj⌋
求对这三个数最少操作多少次使得三个数都变成
n
n
n
分析
先来枚举一下对于第 i i i次操作最大能达到多少。
i | max |
---|---|
1 | 1 |
2 | 1 |
3 | 3 |
⋯ \cdots ⋯ | ⋯ \cdots ⋯ |
2 n 2n 2n | 2 n − 1 2^{n}-1 2n−1 |
2 n + 1 2n+1 2n+1 | 2 n − 1 2^{n}-1 2n−1 |
(后面两组找规律可得)
对于两个整数
a
a
a和
b
b
b,且
a
<
b
a<b
a<b,如果在第
i
i
i次可以达到
b
b
b,那么也能达到
a
a
a。
所以,思路就是找一个正整数
p
p
p,使得
2
p
−
1
≤
n
2^p-1\le n
2p−1≤n,最后的答案就是
2
n
+
1
2n+1
2n+1
#include<bits/stdc++.h>
#define int long long
#define endl putchar('\n')
using namespace std;
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
void print(int x){
if(x<0)putchar('-'),x=-x;
if(x<10){putchar(x+'0');return;}
print(x/10);
putchar(x%10+'0');
}
int T;
signed main(){
T=read();
while(T--){
int x=read();
int ans=1,i;
for(i=1;i<=64;i++){
ans=ans*2;
if(ans>x)break;
}
print(i*2+1);
endl;
}
}
B - Fibonacci Cubes
题意
有
n
n
n个正方体,第
i
i
i个正方体的棱长为
f
i
f_i
fi,对于
f
i
f_i
fi,有:
f
1
=
1
f
2
=
2
f
i
=
f
i
−
1
+
f
i
−
2
(
f
>
2
)
f_1=1\\ f_2=2\\ f_i=f_{i-1}+f_{i-2}(f>2)
f1=1f2=2fi=fi−1+fi−2(f>2)
有
m
m
m个盒子,第
i
i
i个盒子的长宽高分别为
w
i
w_i
wi,
h
i
h_i
hi,
l
i
l_i
li。
立方体摆放需遵循以下规则:
- 立方体必须与盒子边平行放置;
- 每个立方体必须直接放置在盒底,或叠放在其他立方体上且下方空间必须被完全填满;
- 较大的立方体不能叠放在较小立方体上。
问这些盒子分别能不能按要求装下所有正方体。
分析
由于 n n n个盒子的棱长分别是斐波拉切数列的前 n n n位,所以可以考虑下图:(正方形表示正方体的俯视图,正方形内数字表示正方体的棱长)。
可以发现,对于第
n
n
n个正方体,只要其上还剩下
f
n
−
1
f_{n-1}
fn−1高度的盒子空间,那么就能放下第
n
−
1
n-1
n−1个正方体,对于第
n
−
1
n-1
n−1个正方体以此类推……
最后可以证明,只要能放下第
n
n
n个和第
n
−
1
n-1
n−1个正方体,就能放下所有的正方体。
#include<bits/stdc++.h>
#define endl putchar('\n')
using namespace std;
const int N=1e6+5;
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
void putstr(string s){
for(int i=0;i<s.size();i++)putchar(s[i]);
}
int n,m;
int T;
int w[N],h[N],l[N];
int f[N]={1,1};
signed main(){
T=read();
for(int i=2;i<=10;i++)f[i]=f[i-1]+f[i-2];
while(T--){
n=read(),m=read();
for(int i=1;i<=m;i++)w[i]=read(),h[i]=read(),l[i]=read();
string p="";
for(int i=1;i<=m;i++){
if(f[n]>w[i]||f[n]>h[i]||f[n]>l[i]){//检查第n个正方体
p.push_back('0');
continue;
}
int x=w[i]-f[n],y=h[i]-f[n],z=l[i]-f[n];
if(f[n-1]>x&&f[n-1]>y&&f[n-1]>z){//检查第n-1个正方体
p.push_back('0');
continue;
}
p.push_back('1');
}
putstr(p);
endl;
}
}
C - Equal Values
题意
有 n n n个整数 a 1 a_1 a1, a 2 a_2 a2, a 3 … a n a_3\ldots a_n a3…an,可以进行两种操作:
- 选择位置 i i i,将 a 1 … i − 1 a_{1\ldots i-1} a1…i−1全部变成 a i a_i ai,代价为 ( i − 1 ) ⋅ a i (i-1)\cdot a_i (i−1)⋅ai
- 选择位置
i
i
i,将
a
i
+
1
…
n
a_{i+1\ldots n}
ai+1…n全部变成
a
i
a_i
ai,代价为
(
n
−
i
)
⋅
a
i
(n-i)\cdot a_i
(n−i)⋅ai
求将 n n n个整数全部变成一样的最小代价。
分析
举例两个情况
情况1
5
2
2
5
2
2
5\\2\ 2\ 5\ 2\ 2
52 2 5 2 2
这个时候选择
a
2
a_2
a2向右边变化,代价为
6
6
6,虽然说右边只有
5
5
5这个不同的数字,但是还是得将
5
2
2
5\ 2\ 2
5 2 2三个数全部变化。
可以得出,当两部分相同的数没有相连的时候,互相没有任何影响。
情况2
8
5
4
2
2
2
2
2
1
8\\5\ 4\ 2\ 2\ 2\ 2\ 2\ 1
85 4 2 2 2 2 2 1
有一种方案是选择
a
8
a_8
a8向左边变化,代价为
7
7
7,但明显不是最优的。可选择
a
3
a_3
a3向左变化
a
7
a_7
a7向右变化,代价为
6
6
6,中间由于都是
2
2
2就不用变了。
可以得出,对于相邻数,互相是有影响的,变化时只用取两端的数左右变化就行了。
可以先求出每一个点对应联通块的左右端点,然后记录最小值就行了。
#include<bits/stdc++.h>
#define int long long
#define endl putchar('\n')
using namespace std;
const int N=1e6+5;
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
void print(int x){
if(x<0)putchar('-'),x=-x;
if(x<10){putchar(x+'0');return;}
print(x/10);
putchar(x%10+'0');
}
int n;
int T;
int a[N];
int f[N];
int k[N];
signed main(){
T=read();
while(T--){
n=read();
for(int i=1;i<=n;i++)a[i]=read(),f[i]=i,k[i]=i;
for(int i=2;i<=n;i++){
if(a[i]==a[i-1])f[i]=f[i-1];
}
for(int i=n-1;i>=1;i--){
if(a[i]==a[i+1])k[i]=k[i+1];
}
int mn=1e18;
for(int i=1;i<=n;i++){
mn=min(mn,(f[i]-1)*a[i]+(n-k[i])*a[i]);
}
print(mn);
endl;
}
}
D - Creating a Schedule
题意
有
n
n
n个班级和
m
m
m间教室,教室编号为一个至少三位的数,出去最后两位剩下的表示教室所在的楼层。
这
n
n
n个班级每天都有
6
6
6节课,且每个班级的第
k
k
k节课在同一时间进行,两个班级不能同时在同一件教室上课。
请你设计一个课程表,使每个班级学生上下楼移动的距离最大。
分析
先考虑两个班级的情况。
当只有两个班级的时候,可以考虑让两个班级在最高层的最底层之间交替上课,可以实现移动最大化。
当出现第三个班级的时候,可以考虑让其在次大层和次小层移动,获得最大收益。
第四层同理。
以此类推。
#include<bits/stdc++.h>
#define int long long
#define psp putchar(' ')
#define endl putchar('\n')
using namespace std;
const int N=1e6+5;
int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*f;
}
void print(int x){
if(x<0)putchar('-'),x=-x;
if(x<10){putchar(x+'0');return;}
print(x/10);
putchar(x%10+'0');
}
int n,m;
int T;
int f[N];
signed main(){
T=read();
while(T--){
n=read(),m=read();
for(int i=1;i<=m;i++)f[i]=read();
sort(f+1,f+1+m);
int p=(n+1)>>1;
for(int i=1;i<=p;i++){
if(n>1){//判断剩下奇数个还是偶数个
for(int j=1;j<=3;j++)print(f[i]),psp,print(f[m-i+1]),psp;
endl;
for(int j=1;j<=3;j++)print(f[m-i+1]),psp,print(f[i]),psp;
endl;
n-=2;
}
else{
for(int j=1;j<=3;j++)print(f[i]),psp,print(f[m-i+1]),psp;
endl;
}
}
}
}