前置知识:

  • 搜索
  • 队列
  • 递归
  • (提高难度)记忆化搜索

T1:P1226 【模板】快速幂

暴力想法:\(a\times a\) 进行 \(b\) 次,每次 \(a\times a\mod p\)​。

结果:TLE。

正解:

运用二分、倍增的算法,将每次需要乘的 \(p\) 分解为:

\[\begin{cases}
\frac{p}{2}\ \ \ p\mod 2=0
\\ \\
\frac{p}{2}+1\ \ \ p\mod =1
\end{cases}
\]

然后,若担心溢出,则每次都 \(\mod p\) 一下,使得答案永远 \(< p\)。

代码:

#include<bits/stdc++.h>
using namespace std;
long long n,k;
unsigned long long p;
unsigned long long ans;
unsigned long long tpow(long long k1)
{
if(k1==0)
{
return 1;
}
if(k1%2==0)
{
unsigned long long t=tpow(k1/2)%p;
return (t*t)%p;
}
else
{
unsigned long long t=tpow(k1/2)%p;
return ((t*t)%p*n)%p;
}
}
int main(){
scanf("%d%d%lld",&n,&k,&p);
ans=tpow(k);
printf("%d^%d mod %lld=",n,k,p);
printf("%llu\n",ans%p);
return 0;
}

P1434 [SHOI2002] 滑雪

思路:

首先第一感是暴力深搜。而深搜宗旨是“一条路搜到底,不撞南墙不回头”。所以会浪费大量时间。在本题即为时间超限。

考虑优化时间复杂度。采取记忆化搜索。

记忆化搜索:将搜索到的每个节点后最优结果都存在数组 \(f\) 中。

具体:

放在本题中,即为设 \(f_{i,j}\) 表示走到 \((i,j)\) 目前最长滑雪区域。

当深搜到 \((x,y)\) 时,都首先判断该节点的 \(f_{x,y}\) 数组是否已经被更新,若更新过则直接返回 \(f_{x,y}\),否则通过正常搜索来更新 \(f_{x,y}\)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=105,MAXM=105;
int a[MAXN][MAXM],f[MAXN][MAXM];
int nxt[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
int n,m,ans;
inline int Read()
{
int num=0,r=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
{
r=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
num=num*10+ch-'0';
ch=getchar();
}
return num*r;
}
int solve(int x,int y)
{
if(x<1||x>n||y<1||y>m)
{
return 0;
}
if(f[x][y]!=0)
{
return f[x][y];
}
f[x][y]=1;
for(int i=0;i<4;i++)
{
if(a[x][y]<a[x+nxt[i][0]][y+nxt[i][1]])
{
f[x][y]=max(f[x][y],solve(x+nxt[i][0],y+nxt[i][1])+1);
}
}
return f[x][y];
}
int main(){
n=Read();
m=Read();
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
a[i][j]=Read();
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
ans=max(ans,solve(i,j));
}
}
printf("%d\n",ans);
return 0;
}

P1706 全排列问题

  • 经典深搜。

(具体可以查看《啊哈!算法》搜索)

模板深搜,再加上一个数组,\(book[i]\) 表示 \(i\) 这个数字是否已经被输出。

若没有输出,则输出;若已经输出,则跳过。

正常回溯。

由于思路不易简述,在代码中注释解释。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=15;
bool vis[N];
int a[N],n;
void dfs(int u,int step)
{
if(step>n)//已经输出超过n个,输出后结束
{
for(int i=1;i<=n;i++)
printf("%5d",a[i]);//%5d 即为每个数字占5个位置
putchar('\n');
return;
}
for(int i=1;i<=n;i++)//枚举
{
if(vis[i]) continue;//如果已经处理过
vis[i]=true;//标记为已处理
a[step]=i;
dfs(i,step+1);
vis[i]=false;//回溯
}
return;
}
int main(){
scanf("%d",&n);
dfs(1,1);
return 0;
}

P1149 [NOIP2008 提高组] 火柴棒等式

还是可以参考《啊哈!算法》搜索章。

首先分析题目。

由于数据不大(\(n\le 24\))。考虑暴力枚举。

由于 += 各需要 \(2\) 根火柴棒,所以题目就转化为:

每个数字都需要相应的火柴棒数,组成 \(a,b,c\) 三个数字,必须用完 \(n-4\) 根火柴棒,求有多少种方法满足 \(a+b=c\)。

方法:

枚举简单暴力。

第一层循环枚举 \(a\),第二层循环枚举 \(b\)。由于 \(c=a+b\),所以直接算出。

算出 \(a,b,c\) 后,算出每个数字需要的火柴棒数量,判断是否等于 \(n-4\)。

代码:

#include<iostream>
#include<cstdio>
int fun(int x)
{
int num=0;
int f[10]={6,2,5,5,4,5,6,3,7,6};//0~9共需要的火柴棒数
while(x/10!=0)
{
num+=f[x%10];
x/=10;
}
num+=f[x];
return num; }
int main(){
int a,b,c,m,sum=0;
scanf("%d",&m);
for(a=0;a<=1111;a++)
{
for(b=0;b<=1111;b++)
{
c=a+b;
if(fun(a)+fun(b)+fun(c)==m-4)
{
sum++;
}
}
}
printf("%d",sum);
return 0;
}

P1219 [USACO1.5] 八皇后 Checker Challenge

由于每个棋子放下后,行列对角线都不可以放,所以可以用 \(3\) 个数组标记。具体如下。

b[i] 表示第 \(i\) 列可不可放棋子。

c[i+j]d[i-j+n] 标记对角线。

重点:由于对角线的任意一个点 \((x,y)\) 对于目前节点 \((i,j)\) ,不是 \(i+j=x+y\) 就是 \(i-j+n\) 相等,可以通过此特性来判断。(找规律)

若放在 \((i,j)\)​ 点上,则 b[i]c[i+j]d[i-j+n] 都需要标记。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int ans,n;//ans是用来记录输出次数,题目只要求输出3次
int a[15];//每一行
bool b[15],c[40],d[40];//标记数组,b数组标记那一列,c和d数组标记对角线
void print()//打印函数
{
for(int j=1;j<=n;j++)
{
printf("%d ",a[j]);
}
puts("");
return;
}
void dfs(int i)//重点:深搜dfs
{
if(i>n)//如果一种情况成立(i已经遍历完每一列所有位置)
{
ans++;//记录+1
if(ans<=3)//如果<=3才输出,否则就是+1而已
{
print();
}
return;
}
for(int j=1;j<=n;j++)//枚举每一列
{
if(!b[j]&&!c[i+j]&&!d[i-j+n])//如果这个点没有被其他皇后给攻击到
{
//标记ing ……
b[j]=true;
c[i+j]=true;
d[i-j+n]=true;
a[i]=j;
dfs(i+1);//继续深搜
//取消标记,回溯ing……
b[j]=false;
c[i+j]=false;
d[i-j+n]=false;
}
}
return;
}
int main(){
scanf("%d",&n);
dfs(1);//记得从1开始
printf("%d\n",ans);
return 0;
}

P1596 [USACO10OCT] Lake Counting S

判断连通块。

解法:

  • 并查集/染色判断

运用二维数组 vis[i][j] 表示 \((i,j)\) 是否属于一个连通块。

每次遇到没有被判断过的节点,都进行染色,最后仅需判断共有多少种颜色即可。

(由于并查集是黄题,所以当然有更简单的方法)

  • 搜索标记

每遇到一个没标记过的点,从此点开始搜索,标记所有搜索到的点。

然后每搜一次答案都加一即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=105;
int n,m,ans;
char ch[MAXN][MAXN];
int nxt[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,-1},{-1,1},{1,1},{-1,-1}};
bool vis[MAXN][MAXN];
void dfs(int x,int y)
{
vis[x][y]=true;
for(int i=0;i<8;i++)
{
int tx=x+nxt[i][0],ty=y+nxt[i][1];
if(tx<1||tx>n||ty<1||ty>m)
continue;
if(vis[tx][ty]||ch[tx][ty]=='.') continue;
dfs(tx,ty);
}
return;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>ch[i][j];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(vis[i][j]||ch[i][j]=='.') continue;
dfs(i,j);
ans++;
}
}
printf("%d\n",ans);
return 0;
}

P1605 迷宫

搜索模板题。

从起始点 \((sx,sy)\) 开始暴力深搜(由于数据过小,不需要记忆化),直接打深搜模板,每搜到 \((fx,fy)\) 答案加一。

代码:

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,t;
int a[51][51],book[51][51];
int startx,starty,overx,overy,num;
int x[15][3];
void dfs(int x,int y,int step)
{
int tx,ty;
int next[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
if(x==overx&&y==overy)
{
num++;
return;
}
for(int i=0;i<=3;i++)
{
tx=x+next[i][0];
ty=y+next[i][1];
if(tx<1||tx>n||ty<1||ty>m)
{
continue;
}
if(a[tx][ty]==0&&book[tx][ty]==0)
{
book[tx][ty]=1;
dfs(tx,ty,step+1);
book[tx][ty]=0;
}
}
}
int main(){
cin>>n>>m>>t;
cin>>startx>>starty>>overx>>overy;
for(int i=1;i<=t;i++)
{
cin>>x[i][1];
cin>>x[i][2];
a[x[i][1]][x[i][2]]=1;
}
book[startx][starty]=1;
dfs(startx,starty,1);
cout<<num<<endl;
return 0;
}

P1739 表达式括号匹配

更具体的讲解在这里,不是我写的

栈应用模板题。

因为与解题有关的,只有小括号,也就是说,在处理字符串时,可以无视其他字符。

因为仅有小括号,可以不用栈,用暴力:

枚举每个字符,统计目前左括号跟右括号的个数,若在任意时刻,右括号个数 > 小括号个数,则不满足

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
string s;
int a,b;
int main(){
cin>>s;
for(int i=0;i<s.size();i++)
{
if(a==0&&b==0)
{
if(s[i]==')')
{
puts("NO");
return 0;
}
}
if(b>a)
{
puts("NO");
return 0;
}
if(s[i]=='(')
{
a++;
}
if(s[i]==')')
{
b++;
}
}
if(a==b)
{
puts("YES");
return 0;
}
puts("NO");
return 0;
}

另一种思路:

由于若该表达式合法,则在一个右括号出现后,上一个没被匹配的括号如果不是有剩余的左括号,则该表达式不合法。如果是,则表示这俩括号已被匹配。

根据此性质,可想到用来维护。

代码:

#include<bits/stdc++.h>
using namespace std;
string s;
stack<char> st;
int s_size;
bool check()
{
st.push('#');//避免访问到空栈
for(int i=0;i<s_size;i++)
{
if(s[i]=='@')
break;
if(s[i]!='('&&s[i]!=')') continue;
if(s[i]=='(')
st.push('(');
if(s[i]==')')
{
if(st.top()=='(')
st.pop();
else
return false;
}
}
if(st.top()=='#')
return true;
return false;
}
int main(){
cin >> s;
s_size=s.size();
if(check())
printf("YES\n");
else
printf("NO\n");
return 0;
}

B3616 【模板】队列

考察队列操作。

操作如题意。更细致请查阅oiwiki

插入:q.push(x)

弹出队首:q.pop()

查找队首元素:q.front()

元素个数:q.size()

直接按照上述操作即可。不贴代码。

P1535 [USACO08MAR] Cow Travelling S

记忆化搜索/剪枝。

设 \(f_{i,j,t}\) 为走到 \((i,j)\) 所需要的时间 \(t\) 时可以到达终点的路线数。

类似于滑雪那道题。

还是正常深搜,搜到终点则判断:

若到达终点 \((x,y)\) 的时间恰好为 \(t\),则 \(f_{x,y,t}\) 为 \(1\),否则为 \(0\)。

然后就正常的四个方向搜索 dfs(tx,ty,t-1)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=105,M=105,T=20;
int n,m,t,stx,sty,spx,spy,f[N][M][T];
char ch[N][M];
int nxt[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int dfs(int x,int y,int t)
{
if(f[x][y][t]!=-1)
return f[x][y][t];
if(t==0)
{
if(x==spx&&y==spy)
return f[x][y][t]=1;
return f[x][y][t]=0;
}
int tx,ty,tmp=0;
for(int i=0;i<4;i++)
{
tx=x+nxt[i][0];ty=y+nxt[i][1];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&ch[tx][ty]=='.')
tmp+=dfs(tx,ty,t-1);
}
return f[x][y][t]=tmp;
}
int main(){
scanf("%d%d%d",&n,&m,&t);
memset(f,-1,sizeof(f));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>ch[i][j];
scanf("%d%d%d%d",&stx,&sty,&spx,&spy);
printf("%d\n",dfs(stx,sty,t));
return 0;
}

三牧校队训练题目 Solution的更多相关文章

  1. 【FJ省队训练&&NOIP夏令营】酱油&&滚粗记

    FJOI2016省队训练滚粗记 2016.07.03~2016.07.06(Day1~5) 在学校期末考.因为才省选二试too young too simple爆蛋了所以下半个学期只能滚回去读文化课, ...

  2. Java实现 蓝桥杯 算法训练 Pollution Solution

    试题 算法训练 Pollution Solution 问题描述 作为水污染管理部门的一名雇员,你需要监控那些被有意无意倒入河流.湖泊和海洋的污染物.你的其中一项工作就是估计污染物对不同的水生态系统(珊 ...

  3. HDU6333-2018ACM暑假多校联合训练1002-Harvest of Apples-莫队+费马小定理

    题意很简单啦,求S(n,m)的值 通过打表我们可以知道 S(n + 1, m) = S(n, m) * 2 - C(n, m); S(n - 1, m) = (S(n, m) + C(n - 1, m ...

  4. hdu 5381 The sum of gcd 2015多校联合训练赛#8莫队算法

    The sum of gcd Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) T ...

  5. zju 校队选拔 被虐记

    选拔已经开始了三天才想起来写游记 QAQ.. 7.12 弱弱的Sky_miner来到了ZJU,过程中被热成狗... 然后见到了无数大二大三的大佬们,过程中被热成狗... 后来听靖哥哥说集训的注意事项, ...

  6. 2017多校联合训练2—HDU6054--Is Derek lying?(思维题)

    Is Derek lying? Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  7. 2013 CSU校队选拔赛(1) 部分题解

    A: Decimal Time Limit: 1 Sec   Memory Limit: 128 MB Submit: 99   Solved: 10 [ Submit][ Status][ Web ...

  8. HDU 4643 GSM 暑期多校联合训练第五场 1001

    点击打开链接 我就不说官方题解有多坑了 V图那么高端的玩意儿 被精度坑粗翔了 AC前 AC后 简直不敢相信 只能怪自己没注意题目For the distance d1 and d2, if fabs( ...

  9. 2017 ACM暑期多校联合训练 - Team 9 1008 HDU 6168 Numbers (模拟)

    题目链接 Problem Description zk has n numbers a1,a2,...,an. For each (i,j) satisfying 1≤i<j≤n, zk gen ...

  10. 2017ACM暑期多校联合训练 - Team 7 1002 HDU 6121 Build a tree (深搜+思维)

    题目链接 Problem Description HazelFan wants to build a rooted tree. The tree has n nodes labeled 0 to n− ...

随机推荐

  1. 【漏洞分析】Li.Fi攻击事件分析:缺乏关键参数检查的钻石协议

    背景信息 2024 年 7 月 16日,Li.Fi 协议遭受黑客攻击,漏洞成因是钻石协议中 diamond 合约新添加的 facet 合约没有对参数进行检查,导致 call 函数任意执行.且 diam ...

  2. GIS前沿技术

    无论是初步接触到GIS的学生,还是对GIS已经有一定的了解的从业者,肯定都非常关心两个问题:GIS有没有发展前景,GIS有哪些应用价值? 关于这两个问题,笔者的答案是GIS作为一门融合了空间数据采集. ...

  3. Go 使用 Cobra 构建 CLI 程序

    使用 cobra-cli 搭建手脚架 # 安装 cobra-cli go install github.com/spf13/cobra-cli@latest # 创建一个应用 mkdir myapp ...

  4. M1 Mac安装anaconda3

    1.正常安装 首先进入官网https://www.anaconda.com/ 下载,安装 自行大胆的安装 2.环境配置 直接安装完成后,代码文件的存储路径为默认路径,为了更好的管理代码文件我们需要更换 ...

  5. 从pytest源码的角度分析pytest工作原理

    从pytest源码的角度分析pytest工作原理 从 pytest 源代码的角度来分析其工作原理,我们需要关注几个关键的部分,特别是 pytest 的启动过程以及测试的收集与执行.下面是基于 pyte ...

  6. XML 教程——检视阅读

    基本 XML 简介 XML 指可扩展标记语言(eXtensible Markup Language). XML 被设计用来传输和存储数据.HTML 被设计用来显示数据. 什么是 XML? XML 指可 ...

  7. PyCharm2024 专业版激活设置中文

    PyCharm2024 专业版激活设置中文 官网下载最新版:https://www.jetbrains.com/zh-cn/pycharm/download 「hack-jet激活idea家族.zip ...

  8. 论文写作:“et al.”和“etc.”在英语中的区别

    "et al."和"etc."在英语中有不同的用法和含义.以下是它们的区别和具体用法: et al. "et al."是拉丁短语" ...

  9. 《Python数据可视化之matplotlib实践》 源码 第四篇 扩展 第十三章

    图  13.10 import matplotlib.pyplot as plt import matplotlib as mpl import numpy as np mpl.rcParams[&q ...

  10. 【转载】 自然梯度法(Natural Gradient)

    原文地址: https://blog.csdn.net/philthinker/article/details/80615122 ----------------------------------- ...