总结:正常难度的欢乐笔试
T1
- 题目大意:给出 n n n个任务的失效时间和价值(失效后完成便无法获得价值),每分钟只能做一个任务,求出最大的价值和
- 数据范围 n < = 1 e 6 n<=1e6 n<=1e6
反悔贪心模板题:
首先对于所有任务按照失效时间从小到大进行排序,使用一个集合s表示为当前所选的任务价值。扫一遍所有的任务,如果只能选择一个加入的话,就将当前任务加入集合中,同时将集合中最小的一个元素取出。代表着取消了价值最小的操作,换为现在这个操作,进行操作的同时计算贡献即可。
代码实现:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define maxn 1000005
#define ins insert
#define pb push_back
#define inf 1e9
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+c-'0',c=getchar();
return w==1?x:-x;
}
multiset <ll> s;
multiset <ll>::iterator it;
struct node{ll s,w;}p[maxn];
ll n,ans;
inline bool cmp(node a,node b)
{
if(a.s!=b.s) return a.s<b.s;
return a.w>b.w;
}
int main()
{
n=read(); rep(i,1,n) p[i].s=read(),p[i].w=read();
sort(p+1,p+n+1,cmp); int nw=1;
rep(i,1,n)
{
s.ins(p[nw].w); ans+=p[nw].w; nw++;
while(p[nw].s==i)
{
s.ins(p[nw].w); ans+=p[nw].w; nw++;
it=s.begin(); ans-=(*it); s.erase(it);
}
if(nw>n) break;
}
cout<<ans<<endl;
return 0;
}
/*
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
15*/
T2
- 题目大意:给出 n n n个节点, m m m条边的带权有向图,给出一个起点s,问是否能访问到所有点,能的话输出最长路径。
- 数据范围 n < = 100 n<=100 n<=100
记忆化搜索模板题:
使用
d
p
[
u
]
dp[u]
dp[u]表示从u节点开始的最长路径,记忆化搜索即可,具体实现看代码大家就明白了…
代码实现:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define maxn 1000005
#define ins insert
#define pb push_back
#define inf 1e9
using namespace std;
inline int read()
{
int x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+c-'0',c=getchar();
return w==1?x:-x;
}
int n,m,s,vis[maxn],dfn[maxn],cnt;
ll dp[maxn];
struct node{int to,w;};
vector <node> mp[maxn];
inline ll dfs(int u)
{
if(dp[u]) return dp[u];
if(!dfn[u]) dfn[u]=1,cnt++;
ll tmp=0;
for(auto v:mp[u])
{
if(vis[v.to]) continue;
vis[v.to]=1;
tmp=max(tmp,dfs(v.to)+v.w);
vis[v.to]=0;
}
return dp[u]=tmp;
}
int main()
{
n=read(); m=read(); s=read(); //n点数 m边数 s为起点
rep(i,1,m)
{
int u=read(),v=read(),w=read();
mp[u].pb({v,w});
}
vis[s]=1; dfs(s);
if(cnt==n) cout<<dp[s]<<endl; else puts("-1");
return 0;
}
/*
4 3 1
1 2 15
1 3 7
3 4 9
16
*/
T3
- 题目大意:在中国象棋中,给出大小为 n ∗ m n*m n∗m的棋盘,棋盘上有一些障碍点,以及一匹马在S处要到T点,给出中国象棋中跳马的规则,问至少需要多少步才能跳到T点
- 数据范围 n , m < = 150 n,m<=150 n,m<=150
BFS模板题:
是每场笔试都会有的模拟题,考虑
d
[
x
]
[
y
]
d[x][y]
d[x][y]表示从S点到
(
x
,
y
)
(x,y)
(x,y)的最短路,然后BFS处理即可,具体实现见代码
代码实现:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define maxn 1000005
#define ins insert
#define pb push_back
#define inf 1e9
using namespace std;
inline int read()
{
int x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+c-'0',c=getchar();
return w==1?x:-x;
}
char mp[155][155];
int n,m,sx,sy,tx,ty,d[155][155];
struct node{int x,y;};
queue <node> q;
const int kx[8]={1,-1,1,-1,-2,-2,2,2};
const int ky[8]={-2,-2,2,2,1,-1,1,-1};
int main()
{
n=read(); m=read(); rep(i,1,n) scanf("%s",mp[i]+1);
rep(i,1,n) rep(j,1,m) d[i][j]=inf;
rep(i,1,n) rep(j,1,m)
{
if(mp[i][j]=='H') sx=i,sy=j,d[i][j]=0,q.push({i,j});
if(mp[i][j]=='T') tx=i,ty=j;
}
while(!q.empty())
{
auto u=q.front(); q.pop();
rep(k,0,7)
{
int xx=u.x+kx[k],yy=u.y+ky[k];
if(xx<=0||xx>n||yy<=0||yy>m||d[xx][yy]!=inf||mp[xx][yy]=='#') continue;
if((k==0||k==1)&&mp[u.x][u.y-1]=='#') continue;
if((k==2||k==3)&&mp[u.x][u.y+1]=='#') continue;
if((k==4||k==5)&&mp[u.x-1][u.y]=='#') continue;
if((k==6||k==7)&&mp[u.x+1][u.y]=='#') continue;
d[xx][yy]=d[u.x][u.y]+1; q.push({xx,yy});
}
}
if(d[tx][ty]==inf) puts("-1"); else cout<<d[tx][ty]<<endl;
return 0;
}
/*
5 13
........H...#
........#....
.....#.......
.#...........
..........T#.
4
*/
END