T1
做厌了乘法计算题的贝茜,自创了一种新的乘法运算法则。在这套法则里,
A × B A\times B A×B 等于一个取自 A、一个取自 B 的所有数字对的乘积的和。比方说, 123 × 45 123\times45 123×45 等于
1 × 4 + 1 × 5 + 2 × 4 + 2 × 5 + 3 × 4 + 3 × 5 = 54 1\times4 + 1\times5 + 2\times4 + 2\times5 + 3\times4 + 3\times5 = 54 1×4+1×5+2×4+2×5+3×4+3×5=54。对于 2 个给定的数 A、B
( 1 ≤ A , B ≤ 1 0 9 1\leq A,B\leq 10^9 1≤A,B≤109),你的任务是,用新的乘法法则计算 A*B 的值。
我才不告诉你我高级班就做过了呢 q w q qwq qwq。。。
#include <bits/stdc++.h>
using namespace std;
int main(){
long long a,b,z=0,n,m;
cin>>a>>b;
m=a;
while(m!=0){
n=b;
while(n!=0){
z=z+(m%10)*(n%10);
n=n/10;
}
m=m/10;
}
cout<<z;
return 0;
}
纯粹的模拟
T2
给定一个由 a-z 和
*
组成的字符串,其中*
可以被替代成任何 a-z 中的字符。
询问将*
替换后字典序最小的回文字符串,无解输出-1。
尺取好啊!
从 2 2 2 边往中间扫。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x*=-1;
if(x>9)write(x/10);
putchar(x%10+48);
}
template<typename T>inline void writen(T x){
write(x);
puts("");
}
string st;
void work(int l,int r){
if(st[l]=='*'){
if(st[r]=='*')st[l]=st[r]='a';
else st[l]=st[r];
}else{
if(st[r]=='*')st[r]=st[l];
else if(st[l]!=st[r]){
puts("-1");
exit(0);
}
}
}
int main(){
cin>>st;
int n=st.size();
st=' '+st;
int l=1,r=n;
while(l<=r){
work(l,r);
l++;r--;
}
for(int i=1;i<=n;i++)cout<<st[i];
return 0;
}
T3
有 6 种不同的硬币,现在已知:
- 消耗任意 4 种硬币各一枚可以换一个礼品;
- 消耗任意 5 种硬币各一枚可以换两个礼品;
- 消耗任意 6 种硬币各一枚可以换四个礼品。
有 n 个人,告诉你每个人每种硬币的数量,问每个人最多可以换得到的礼品个数。
一眼贪心
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x*=-1;
if(x>9)write(x/10);
putchar(x%10+48);
}
template<typename T>inline void writen(T x){
write(x);
puts("");
}
ll a[12];
int main(){
int T;
read(T);
while(T--){
for(int i=1;i<=6;i++)read(a[i]);
sort(a+1,a+6+1);
ll ans=(a[1]-a[0])*4+(a[2]-a[1])*2+(a[3]-a[2])*1;
writen(ans);
}
return 0;
}
T4
贝茜听说了一个骇人听闻的消息:一场流星雨即将袭击整个农场,由于流星
体积过大,它们无法在撞击到地面前燃烧殆尽,届时将会对它撞到的一切东西
造成毁灭性的打击。很自然地,贝茜开始担心自己的安全问题。以 FJ 牧场中最
聪明的奶牛的名誉起誓,她一定要在被流星砸到前,到达一个安全的地方(也就
是说,一块不会被任何流星砸到的土地)。如果将牧场放入一个直角坐标系中,
贝茜现在的位置是原点,并且,贝茜不能踏上一块被流星砸过的土地。
根据预报,一共有 M 颗流星(1 <= M <= 50,000)会坠落在农场上,其中第 i 颗
流星会在时刻 T_i (0 <= T_i <= 1,000)砸在坐标为(X_i, Y_i)
(0 <= X_i <= 300;0 <= Y_i <= 300)的格子里。流星的力量会将它所在的格子
,以及周围 4 个相邻的格子都化为焦土,当然贝茜也无法再在这些格子上行走。
贝茜在时刻 0 开始行动,它只能在第一象限中,平行于坐标轴行动,每 1 个时刻中,
,她能移动到相邻的(一般是 4 个)
格子中的任意一个,当然目标格子要没有被烧焦才行。如果一个格子在时刻 t 被
流星撞击或烧焦,那么贝茜只能在 t 之前的时刻在这个格子里出现。
请你计算一下,贝茜最少需要多少时间才能到达一个安全的格子。
传统的搜索
应该没什么问题
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x*=-1;
if(x>9)write(x/10);
putchar(x%10+48);
}
template<typename T>inline void writen(T x){
write(x);
puts("");
}
int n,a[1010][1010],h[1010][1010],xx;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
void work(int x,int y,int t){
a[x][y]=min(a[x][y],t);
for(int i=0;i<4;i++){
int tx=x+dx[i],ty=y+dy[i];
if(tx>=0&&ty>=0)a[tx][ty]=min(a[tx][ty],t);
}
}
queue<int>x;
queue<int>y;
queue<int>s;
int main(){
memset(a,0x3f,sizeof(a));xx=a[0][0];
read(n);
for(int i=1;i<=n;i++){
int x,y,t;
read(x),read(y),read(t);
work(x,y,t);
}h[0][0]=1;
x.push(0);
y.push(0);
s.push(0);
while(x.size()){
//cout<<x.front()<<" "<<y.front()<<" "<<s.front()<<endl;
for(int i=0;i<4;i++){
int tx=x.front()+dx[i],ty=y.front()+dy[i];
if(tx>=0&&ty>=0&&s.front()+1<a[tx][ty]&&!h[tx][ty]){
h[tx][ty]=1;
if(a[tx][ty]==xx){
//cout<<x.front()<<" "<<y.front()<<" "<<a[0][2]<<endl;
cout<<s.front()+1;
return 0;
}
x.push(tx);
y.push(ty);
s.push(s.front()+1);
}
}
x.pop();
y.pop();
s.pop();
}puts("-1");
return 0;
}
T5
给你一个等边三角形,每条边长都是 x,每次操作可以缩小其中一条边的长度,并且三角形不
能退化成直线,询问最少多少次操作可以把这个三角形变成边长为 y 的等边三角形。
想了好久,终于想了出来。
刚开始没想出来倒着推,突然,我把整页的草稿纸反着看了一下,就有了灵感,真的是一道好题。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x*=-1;
if(x>9)write(x/10);
putchar(x%10+48);
}
template<typename T>inline void writen(T x){
write(x);
puts("");
}
int main(){
int x,a,b,c,s=0;
read(x);
read(a);
b=c=a;
while(a!=x||b!=x||c!=x){
//cout<<a<<" "<<b<<" "<<c<<endl;
if(a<=b&&a<=c)a=b+c-1;
else if(b<=a&&b<=c)b=a+c-1;
else if(c<=a&&c<=b)c=a+b-1;
a=min(a,x);
b=min(b,x);
c=min(c,x);
//cout<<a<<" "<<b<<" "<<c<<endl;
s++;
}cout<<s;
return 0;
}
T6
FJ 打算好好修一下农场中某条凹凸不平的土路。按奶牛们的要求,修好后的
路面高度应当单调上升或单调下降,也就是说,高度上升与高度下降的路段不能
同时出现在修好的路中。
整条路被分成了 N 段,N 个整数 A_1, … , A_N (1 <= N <= 2,000)依次描述
了每一段路的高度(0 <= A_i <= 1,000,000,000)。FJ 希望找到一个恰好含 N 个
元素的不上升或不下降序列 B_1, … , B_N,作为修过的路中每个路段的高度。
由于将每一段路垫高或挖低一个单位的花费相同,修路的总支出可以表示为:
|A_1 - B_1| + |A_2 - B_2| + … + |A_N - B_N|
请你计算一下,FJ 在这项工程上的最小支出是多少。FJ 向你保证,这个支出
不会超过 2^31-1。
重点来了!!!敲黑板!!!
首先,我们需要一个性质。这个性质是最终的所有数都源自于原来的数列。
为什么?首先,我们证明一下。
我们从 3 3 3 个数开始想,假设这 3 3 3 个数是 a , b , c a,b,c a,b,c。
- a < b & b < c & a < c a<b \And b<c \And a<c a<b&b<c&a<c
- 这种情况,比方说
7 8 9
,之后,我们的方案是7 8 9
是最优方案之一。
- a > b & b > c & a > c a>b \And b>c \And a>c a>b&b>c&a>c
- 这种情况,比方说
7 6 5
,之后,我们的方案是7 6 5
是最优方案之一。
- a < b & b > c & a < c a<b \And b>c \And a<c a<b&b>c&a<c
- 这种情况,比方说
1 9 7
,之后,我们的方案是1 7 9
是最优方案之一。
- a < b & b > c & a > c a<b \And b>c \And a>c a<b&b>c&a>c
- 这种情况,比方说
8 9 7
,之后,我们的方案是9 9 7
是最优方案之一。
- a > b & b < c & a > c a>b \And b<c \And a>c a>b&b<c&a>c
- 这种情况,比方说
7 5 9
,之后,我们的方案是5 5 9
是最优方案之一。
- a > b & b < c & a < c a>b \And b<c \And a<c a>b&b<c&a<c
- 这种情况,比方说
7 5 6
,之后,我们的方案是7 5 5
是最优方案之一。
之后,我们考虑给数列加一个数 d d d。我们刚才已经证明了, a , b , c a,b,c a,b,c 3个数,任意排列都是最优的。现在,我们来分类讨论。
为了方便,假设都是第 1 1 1 种情况, a < b < c a < b < c a<b<c,最优排列是 a , b , c a,b,c a,b,c
- d ≤ a d \leq a d≤a
这种情况,显然,对不对。比如 a , b , c a,b,c a,b,c 的最优排列是 3 , 5 , 7 , 9 3,5,7,9 3,5,7,9, d = 2 d=2 d=2。我觉得不用解释了。
- d ≥ a & d ≤ b d\geq a \And d\leq b d≥a&d≤b
这种情况,显然,对不对。比如 a , b , c a,b,c a,b,c 的最优排列是 3 , 5 , 7 , 9 3,5,7,9 3,5,7,9, d = 4 d=4 d=4。我觉得不用解释了。
- d ≥ b & d ≤ c d\geq b \And d\leq c d≥b&d≤c
这种情况,显然,对不对。比如 a , b , c a,b,c a,b,c 的最优排列是 3 , 5 , 7 , 9 3,5,7,9 3,5,7,9, d = 6 d=6 d=6。我觉得不用解释了。
- d ≥ c d\geq c d≥c
这种情况,显然,对不对。比如 a , b , c a,b,c a,b,c 的最优排列是 3 , 5 , 7 , 9 3,5,7,9 3,5,7,9, d = 10 d=10 d=10。我觉得不用解释了。
竟然打了 4 4 4 个显然,只不过确实显然。
然后,如果您就可以感性理解一下,我们继续加数,肯定依然是最优。
这样代码就很好写了。
大概这样:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x*=-1;
if(x>9)write(x/10);
putchar(x%10+48);
}
template<typename T>inline void writen(T x){
write(x);
puts("");
}
const int MAXN=2e3+10;
int n,a[MAXN],b[MAXN],ans,f[MAXN][MAXN];
bool cmp1(int x,int y){
return x>y;
}
bool cmp2(int x,int y){
return x<y;
}
int getans(){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=INT_MAX;
for(int k=1;k<=j;k++)
f[i][j]=min(f[i][j],f[i-1][k]+abs(b[i]-a[j]));
}
}
int ans=INT_MAX;
for(int i=1;i<=n;i++)ans=min(ans,f[n][i]);
return ans;
}
int main(){
read(n);
for(int i=1;i<=n;i++)read(a[i]),b[i]=a[i];
sort(a+1,a+n+1,cmp1);
ans=getans();
sort(a+1,a+n+1,cmp2);
ans=min(ans,getans());
cout<<ans;
return 0;
}
您会发现这个算法复杂度是 O ( n 3 ) O(n^3) O(n3) 的,所以,还需要优化。我们发现找最小值,会有很多的重复计算
所以,我们可以把这个算法,优化成 O ( n 2 ) O(n^2) O(n2)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &FF){
T RR=1;FF=0;char CH=getchar();
for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
FF*=RR;
}
template<typename T>inline void write(T x){
if(x<0)putchar('-'),x*=-1;
if(x>9)write(x/10);
putchar(x%10+48);
}
template<typename T>inline void writen(T x){
write(x);
puts("");
}
const int MAXN=2e3+10;
int n,a[MAXN],b[MAXN],ans,f[MAXN][MAXN];
bool cmp1(int x,int y){
return x>y;
}
bool cmp2(int x,int y){
return x<y;
}
int getans(){
for(int i=1;i<=n;i++){
int ans=INT_MAX;
for(int j=1;j<=n;j++){
ans=min(ans,f[i-1][j]);
f[i][j]=ans+abs(b[i]-a[j]);
}
}
int ans=INT_MAX;
for(int i=1;i<=n;i++)ans=min(ans,f[n][i]);
return ans;
}
int main(){
read(n);
for(int i=1;i<=n;i++)read(a[i]),b[i]=a[i];
sort(a+1,a+n+1,cmp1);
ans=getans();
sort(a+1,a+n+1,cmp2);
ans=min(ans,getans());
cout<<ans;
return 0;
}
总结
这场比赛,我终于 A K \color{skyblue}{AK} AK 了!
只不过,分数跟我的预想差距很大。倒数 2 2 2 题,可谓是灵感题吧。(一道是我吃饭的时候想到的,一道是我睡觉的时候想到的)
然后很多人都 A A A 了,看来还是我太弱了吧。