A.三升序列
题目大意:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
对于一个字母矩阵,我们称矩阵中的一个三升序列是指在矩阵中找到三个字母,它们在同一行,同一列,或者在同一 45 度的斜线上,这三个字母从左向右看、或者从上向下看是递增的。
例如,如下矩阵中
YQPD
BKEZ
AFYV
有 BKZ*、BEZ、AFY、AFV、AKP、*DEF 等 6 个三升序列。注意当三个字母是从左下到右上排列时,从左向右看和从上向下看是不同的顺序。
对于下面的 30 行 50 列的矩阵,请问总共有多少个三升序列?
VLPWJVVNNZSWFGHSFRBCOIJTPYNEURPIGKQGPSXUGNELGRVZAG
SDLLOVGRTWEYZKKXNKIRWGZWXWRHKXFASATDWZAPZRNHTNNGQF
ZGUGXVQDQAEAHOQEADMWWXFBXECKAVIGPTKTTQFWSWPKRPSMGA
BDGMGYHAOPPRRHKYZCMFZEDELCALTBSWNTAODXYVHQNDASUFRL
YVYWQZUTEPFSFXLTZBMBQETXGXFUEBHGMJKBPNIHMYOELYZIKH
ZYZHSLTCGNANNXTUJGBYKUOJMGOGRDPKEUGVHNZJZHDUNRERBU
XFPTZKTPVQPJEMBHNTUBSMIYEGXNWQSBZMHMDRZZMJPZQTCWLR
ZNXOKBITTPSHEXWHZXFLWEMPZTBVNKNYSHCIQRIKQHFRAYWOPG
MHJKFYYBQSDPOVJICWWGGCOZSBGLSOXOFDAADZYEOBKDDTMQPA
VIDPIGELBYMEVQLASLQRUKMXSEWGHRSFVXOMHSJWWXHIBCGVIF
GWRFRFLHAMYWYZOIQODBIHHRIIMWJWJGYPFAHZZWJKRGOISUJC
EKQKKPNEYCBWOQHTYFHHQZRLFNDOVXTWASSQWXKBIVTKTUIASK
PEKNJFIVBKOZUEPPHIWLUBFUDWPIDRJKAZVJKPBRHCRMGNMFWW
CGZAXHXPDELTACGUWBXWNNZNDQYYCIQRJCULIEBQBLLMJEUSZP
RWHHQMBIJWTQPUFNAESPZHAQARNIDUCRYQAZMNVRVZUJOZUDGS
PFGAYBDEECHUXFUZIKAXYDFWJNSAOPJYWUIEJSCORRBVQHCHMR
JNVIPVEMQSHCCAXMWEFSYIGFPIXNIDXOTXTNBCHSHUZGKXFECL
YZBAIIOTWLREPZISBGJLQDALKZUKEQMKLDIPXJEPENEIPWFDLP
HBQKWJFLSEXVILKYPNSWUZLDCRTAYUUPEITQJEITZRQMMAQNLN
DQDJGOWMBFKAIGWEAJOISPFPLULIWVVALLIIHBGEZLGRHRCKGF
LXYPCVPNUKSWCCGXEYTEBAWRLWDWNHHNNNWQNIIBUCGUJYMRYW
CZDKISKUSBPFHVGSAVJBDMNPSDKFRXVVPLVAQUGVUJEXSZFGFQ
IYIJGISUANRAXTGQLAVFMQTICKQAHLEBGHAVOVVPEXIMLFWIYI
ZIIFSOPCMAWCBPKWZBUQPQLGSNIBFADUUJJHPAIUVVNWNWKDZB
HGTEEIISFGIUEUOWXVTPJDVACYQYFQUCXOXOSSMXLZDQESHXKP
FEBZHJAGIFGXSMRDKGONGELOALLSYDVILRWAPXXBPOOSWZNEAS
VJGMAOFLGYIFLJTEKDNIWHJAABCASFMAKIENSYIZZSLRSUIPCJ
BMQGMPDRCPGWKTPLOTAINXZAAJWCPUJHPOUYWNWHZAKCDMZDSR
RRARTVHZYYCEDXJQNQAINQVDJCZCZLCQWQQIKUYMYMOVMNCBVY
ABTCRRUXVGYLZILFLOFYVWFFBZNFWDZOADRDCLIRFKBFBHMAXX
题解:
使用dfs暴力找即可,用dir数组标识5个方向:左到右,上到下,左下到右上,左上到右下,右上到左下(右下到左上是不符合要求的)
Code:
#include <bits/stdcpp.h>
using namespace std;
#define ioss ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
char a[35][55];
int dir[5][2]={0,1,1,0,1,1,-1,1,1,-1};
int ans;
bool in(int x,int y){
return x>=1&&x<=30&&y>=1&&y<=50;
}
void solve(int x,int y){
for(int i=0;i<5;++i){
int tx=x,ty=y;
while(in(tx,ty)){
tx+=dir[i][0];
ty+=dir[i][1];
if(a[tx][ty]<=a[x][y])continue;
int ttx=tx,tty=ty;
while(in(ttx,tty)){
ttx+=dir[i][0];
tty+=dir[i][1];
if(a[ttx][tty]<=a[tx][ty])continue;
ans++;
}
}
}
}
int main(){
char c;
for(int i=1;i<=30;++i){
for(int j=1;j<=50;++j){
a[i][j]=getchar();
}
c=getchar();
}
for(int i=1;i<=30;++i){
for(int j=1;j<=50;++j){
solve(i,j);
}
}
cout<<ans; //156159
return 0;
}
B.最优旅行
题目大意:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
中国的高铁四通八达,乘坐方便,小明经常乘坐高铁在城市间旅游。
现在,小明又有了一个长假,他打算继续乘坐高铁旅游。这次,他打算到下面的城市旅游。
上海、广州、长沙、西安、杭州、济南、成都、南京、昆明、郑州、天津、太原、武汉、重庆、南昌、长春、沈阳、贵阳、福州。
小明打算从北京出发,游览以上每个城市正好一次,最终回到北京。在每个城市(除北京外),小明都至少停留 24 小时。而当小明决定从一个城市去往另一个城市时,他只会选择有直接高铁连接的城市,不会在中途换乘转车。
下面是小明可以选择的车次,小明不会选择其他车次。
车次 出发站 到达站 出发时间 到达时间
G169 北京 上海 16:40 22:35
G21 北京 上海 19:08 23:40
G18 上海 北京 17:55 22:36
G68 广州 北京 11:13 21:10
G67 北京 广州 12:13 22:19
G1305 上海 广州 15:25 23:38
G86 广州 上海 08:00 14:50
G6122 广州 长沙 21:00 23:36
G6117 长沙 广州 17:55 20:39
G502 长沙 北京 07:36 14:24
G503 北京 长沙 14:41 21:14
G1359 上海 长沙 15:37 20:59
G1348 长沙 上海 09:00 13:41
G362 西安 上海 08:49 14:45
G1936 上海 西安 16:12 22:54
G87 北京 西安 14:00 18:20
G88 西安 北京 13:30 17:55
G98 西安 广州 09:57 17:39
G836 广州 西安 11:24 20:09
G1404 广州 杭州 15:56 23:25
G20 杭州 北京 07:48 12:20
G39 北京 杭州 19:04 23:22
G7355 上海 杭州 21:30 22:28
G7558 杭州 上海 07:06 08:12
G300 济南 上海 06:50 11:40
G333 北京 济南 19:55 21:55
G336 济南 北京 07:45 09:33
G2056 广州 济南 08:05 18:34
G2058 济南 广州 10:14 20:49
G350 成都 北京 07:00 14:46
G89 北京 成都 06:53 14:38
G1888 成都 南京 11:28 22:00
G7180 上海 南京 10:05 11:29
G7003 南京 上海 08:00 09:39
G7613 南京 杭州 16:19 17:40
G7604 杭州 南京 12:09 13:30
G1540 昆明 南京 10:20 21:14
G1539 南京 昆明 09:05 19:40
G2883 成都 昆明 08:51 14:29
G2884 昆明 成都 12:16 17:57
G1538 昆明 郑州 08:46 18:48
G1537 郑州 昆明 10:38 20:49
G2001 郑州 西安 07:52 10:24
G2002 西安 郑州 08:10 10:29
G2231 西安 重庆 17:06 22:56
G2232 重庆 西安 07:05 12:37
G8594 重庆 成都 06:50 08:07
G8599 成都 重庆 22:12 23:29
G1709 天津 重庆 08:05 19:39
G1710 重庆 天津 10:49 22:45
G8901 北京 天津 22:10 22:45
G8928 天津 北京 19:08 19:46
G2609 天津 太原 10:40 14:15
G2610 太原 天津 14:43 18:12
G1954 太原 上海 12:26 21:17
G1952 上海 太原 08:10 17:28
G686 郑州 太原 13:17 17:16
G688 太原 郑州 17:38 21:38
G1864 太原 杭州 12:50 21:10
G1862 杭州 太原 07:14 15:50
G91 北京 太原 08:40 11:07
G92 太原 北京 08:33 11:00
G694 太原 武汉 16:37 22:29
G692 武汉 太原 09:48 16:00
G1722 武汉 上海 08:00 11:53
G1720 上海 武汉 13:51 17:50
G858 西安 武汉 15:18 19:48
G856 武汉 西安 09:17 14:27
G365 天津 武汉 14:56 20:41
G366 武汉 天津 14:30 20:32
G294 长沙 天津 08:47 16:56
G292 天津 长沙 10:58 18:50
G696 长沙 太原 09:23 17:55
G698 太原 长沙 10:46 18:18
G1391 杭州 昆明 11:43 22:53
G1392 昆明 杭州 09:06 20:18
G1514 昆明 南昌 16:00 22:54
G1511 南昌 昆明 08:25 15:38
G1462 南昌 杭州 12:24 15:28
G1451 杭州 南昌 12:30 15:26
G1244 济南 长春 07:42 15:07
G1242 长春 济南 15:33 22:35
G8033 沈阳 长春 06:42 08:40
G1290 长沙 长春 07:21 21:09
G1292 长春 长沙 08:47 22:08
G400 长春 北京 08:32 14:48
G399 北京 长春 15:20 21:45
G1886 南京 成都 08:07 17:54
G579 南京 长沙 09:27 14:10
G580 长沙 南京 15:53 20:40
G1484 贵阳 南京 07:58 18:02
G2335 南京 贵阳 12:07 21:58
G2105 长沙 贵阳 13:17 16:55
G2116 贵阳 长沙 08:11 11:26
G2201 郑州 成都 07:10 13:19
G2212 成都 郑州 16:57 23:04
G1814 上海 郑州 14:15 18:12
G370 郑州 上海 07:33 12:02
G1274 武汉 沈阳 07:23 19:03
G1272 沈阳 武汉 07:32 19:20
G2869 重庆 昆明 07:43 11:55
G2870 昆明 重庆 14:52 19:09
G1335 重庆 上海 08:48 20:56
G1333 上海 重庆 11:39 23:29
G1759 南昌 重庆 07:08 14:45
G1761 重庆 南昌 15:12 22:23
G1493 南京 南昌 13:00 17:21
G1496 南昌 南京 09:04 13:25
G5314 南昌 福州 08:13 11:09
G5312 福州 南昌 18:30 21:25
G1256 长春 上海 11:53 22:54
G1258 上海 长春 09:08 20:05
G1284 沈阳 成都 07:02 21:47
G1282 成都 沈阳 09:06 23:13
G217 北京 沈阳 13:30 17:15
G218 沈阳 北京 08:11 11:58
G2604 沈阳 太原 15:34 23:00
G2602 太原 沈阳 07:44 15:14
G8664 贵阳 成都 19:15 22:35
G8691 成都 贵阳 11:11 14:31
G2958 贵阳 广州 14:03 20:26
G2960 广州 贵阳 07:27 13:43
G1521 武汉 贵阳 08:01 13:25
G1524 贵阳 武汉 14:23 19:33
G1609 福州 广州 08:16 14:15
G1607 广州 福州 14:55 21:05
G1696 昆明 福州 11:11 22:02
G1698 福州 昆明 08:41 19:28
G1636 福州 上海 12:26 16:55
G1631 上海 福州 07:54 12:15
G1642 福州 杭州 14:45 18:32
G1641 杭州 福州 18:55 22:38
小明出发的时间是第 1 天的中午 12:00。请问,小明游览完以上城市正好一次,最终回到北京,最快需要多少分钟(请注意单位为分钟,请注意除北京外的城市需要至少停留 24 小时,即最少停留 1440 分钟)。
题解:
一共20个城市,使用二进制压缩标识状态,不过还需要加一维现在在哪个城市
dfs搜索+记忆化剪枝
注意:
- 每个城市都只去过一次,最后需要回到北京
- 回到北京后是不需要加24小时的,要记得减掉多加的24小时
Code:
#include <bits/stdcpp.h>
using namespace std;
#define ioss ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define novis(v,sta) !((sta>>(v-1))&1)
struct edge{
int v,next,a,b;
}e[200];
int aim,head[25];
void add(int u,int v,int a,int b){
e[++aim].next=head[u];
head[u]=aim;
e[aim].v=v;
e[aim].a=a;
e[aim].b=b;
}
int f[(1<<20)+10][21];
int ans=0x3f3f3f3f;
void dfs(int u,int sta,int now,int t){
if(u==1&&sta!=0&&sta!=(1<<20)-1)return;
if(t>=f[sta][u])return;
if(t>=ans)return;
f[sta][u]=t;
if(sta==(1<<20)-1){
ans=t;
return;
}
for(int i=head[u];i;i=e[i].next){
int v=e[i].v,a=e[i].a,b=e[i].b;
if(novis(v,sta)){ //没访问过
if(a>now){
if(b>a){
dfs(v,sta|(1<<(v-1)),b,t+b+24*60-now);
}else{
dfs(v,sta|(1<<(v-1)),b,t+b+2*24*60-now);
}
}else{
if(b>a){
dfs(v,sta|(1<<(v-1)),b,t+b+2*24*60-now);
}else{
dfs(v,sta|(1<<(v-1)),b,t+b+3*24*60-now);
}
}
}
}
}
int main(){
int n=20,m=132;
int u,v,a1,a2,b1,b2;
for(int i=1;i<=132;++i){
scanf("%d %d %d:%d %d:%d",&u,&v,&a1,&a2,&b1,&b2);
add(u,v,a1*60+a2,b1*60+b2);
}
memset(f,0x3f,sizeof f);
dfs(1,0,12*60,0);
cout<<ans-24*60; //41613
return 0;
}
C.骰子制造
题目大意:
这个题,题意很不清晰,网上也搜不到相应的题解,就不做了
D.序列求和
题目大意:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
题解:
直接暴力做不出来,(别问我为啥知道)
在草稿纸上列出前几项后发现规律:将一个数质因数分解,每个质因数对应的(指数+1)乘起来就是这个数的因数个数。
大概能感觉到 2,3,5,7 就已经可以构造出大部分的Si了,所以直接四层循环,枚举每个质数的指数,去更新Si的最小值即可。
每层大概枚举到100,以前一直以为1s只能跑1千万次(1e7)的计算量,但实际上如果常数小的话,1个亿(1e8)的运算量也是能很快跑完的。
以下为当时 O(1e8) 的用时:
![image-20230604162550329](https://i-blog.csdnimg.cn/blog_migrate/a83e75644331c73314083a720fa1d753.png)
Code:
#include<bits/stdcpp.h>
using namespace std;
typedef unsigned long long ll;
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans*=a;
a*=a;
b>>=1;
}
return ans;
}
ll ans;
ll res[61];
int l=100;
int main(){
for(int a1=0;a1<=l;a1++){
for(int a2=0;a2<=a1;a2++){
for(int a3=0;a3<=a2;a3++){
for(int a4=0;a4<=a3;a4++){ //后面的指数没必要比前面的大
int t=(a1+1)*(a2+1)*(a3+1)*(a4+1);
if(t<=60){
ll tmp=(ll)(qpow(2,a1)*qpow(3,a2)*qpow(5,a3)*qpow(7,a4));
if(tmp<res[t]||res[t]==0){
res[t]=tmp;
}
}
}
}
}
}
for(int i=1;i<=60;i++) ans+=res[i];
cout<<ans; //292809912969717649
}
E.无方集合
题目大意:
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
小明不是很喜欢完全平方数,他甚至不喜欢加起来是完全平方数的两个数。
今天,他想从 1 到 100 中选择一些数组成一个集合,要求不选择任何一个完全平方数,集合中任意两个数相加也不能是完全平方数。请问,小明最多能选出多少个数。
题解:
dfs+最优化剪枝
剪枝主要就是有一个预测值maybe,就是假如没被标记的数都可以选上的最优情况下贡献的cnt都没有已经存在的ans大的话,就可以return了,可以剪掉很大一部分的枝节!
还有一个就是完全平方数得预处理到200以内,因为99+98差不多就在这个范围内,不能只预处理到100
关于预测数maybe的处理出了点问题,导致我卡了超级久超级久,下一次一定要再细心一点!!
Code:
#include <bits/stdcpp.h>
using namespace std;
#define ioss ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int a[20];
bool bj[1010];
int ans;
void dfs(int now,int cnt,int bg,int maybe){
if(a[bg]-now<=now)bg++;
if(cnt>ans) ans=cnt;
if(now==100)return;
if(cnt+maybe<=ans)return;
if(!bj[now]){
int t[20],tn=0;
for(int i=bg;i<=16;++i){
if(a[i]-now>=100)break;
if(!bj[a[i]-now]){
t[++tn]=a[i]-now;
bj[a[i]-now]=1;
}
}
maybe-=tn;
dfs(now+1,cnt+1,bg,maybe-1);
maybe+=tn;
for(int i=1;i<=tn;++i){
bj[t[i]]=0;
}
}
if(!bj[now])
dfs(now+1,cnt,bg,maybe-1);
else
dfs(now+1,cnt,bg,maybe);
//这个地方卡了超级久!!!如果这个点本来就是被标记过的,那么maybe就不需要再减1了,因为之前标记的时候就已经减过了,再减就减多了,跑出来一直不对
}
int main(){
for(int i=1;i<=16;++i){
a[i]=i*i;
bj[a[i]]=1;
}
dfs(2,0,3,90);
cout<<ans; //36
return 0;
}