题目:Linear Probing(并查集)
解析:
本题简单一点来说,有2的20次方长度的序列,先开始里面元素都为-1,现在有q次操作,给你个t和x,当t为1时,另一个h=x,i=h%n,索引ai,当ai没有被改变过为-1时将x赋值给ai,否则就让h++,一直到达没有改变的元素。q的值范围很大,所以索引遇到了被改变的元素,时间复杂度很大,所以我们遇到了被改变的元素时候要直接跳到没有被改变的元素上去,这里我们可以使用并查集,让被改变的元素直接指到,没有被改变的元素(没有被改变的元素作为父亲)。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
int a[1050006];
int f[1050006];
int find(int x){
if(f[x]==x) return x;
else f[x]=find(f[x]);
return f[x];
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
int q;
cin>>q;
int N=pow(2,20);
memset(a,-1,sizeof(a));
//cout<<a[0];
for(int i=0;i<=N;i++) f[i]=i;
while(q--){
int t,x;
cin>>t>>x;
if(t==2){
cout<<a[x%N]<<endl;
}
else{
int h=x;
int b=h%N;
int bb=find(b);
//cout<<f[b]<<" "<<endl;
while(a[bb%N]!=-1){
f[bb%N]=(bb+1)%N;
bb++;
}
a[bb%N]=x;
}
}
return 0;
}
题目:Connect 6(暴力枚举)
解析:
本题n<=1000很小,直接采取On的平方复杂度暴力枚举,从上往下、从左往右,左斜、右斜。这三个方向只要可以找到6个就输出yes,有时候真的不能把题像太难,套死算法。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
int n;
char a[1003][1003];
int vis[1003][1003];
//int dx[4]={0,0,-1,1},dy[4]={-1,1,0,0};
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin>>a[i][j];
}
}
int lg=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int c=0,m=2;
for(int k=0;k<6&&m>=0;k++){
int xx=k+i;
if(xx>=0&&xx<n){
c++;
if(a[xx][j]=='#') continue;
else{
m--;
}
}
}
if(c==6&&m>=0) lg=1;
c=0,m=2;
for(int k=0;k<6&&m>=0;k++){
int yy=k+j;
if(yy>=0&&yy<n){
c++;
if(a[i][yy]=='#') continue;
else m--;
}
}
if(c==6&&m>=0) lg=1;
c=0,m=2;
for(int k=0;k<6&&m>=0;k++){
int xx=k+i,yy=k+j;
if(yy>=0&&yy<n&&xx>=0&&xx<n){
c++;
if(a[xx][yy]=='#') continue;
else m--;
}
}
if(c==6&&m>=0) lg=1;
c=0,m=2;
for(int k=0;k<6&&m>=0;k++){
int xx=i+k,yy=j-k;
if(yy>=0&&yy<n&&xx>=0&&xx<n){
c++;
if(a[xx][yy]=='#') continue;
else m--;
}
}
if(c==6&&m>=0) lg=1;
if(lg==1) break;
}
if(lg==1) break;
}
if(lg==1){
cout<<"Yes"<<endl;
}
else{
cout<<"No"<<endl;
}
return 0;
}
题目:Stronger Takahashi(BFS)
解析:
这道题需要用到算法(BFS和双端队列)来实现,题意就是路上有障碍物,如果可以直接过就直接过,如果不行,那可以打拳将2*2以内的障碍物清除,消耗一拳。我们就从起点开始搜索,先走没有障碍物的格子,放入队列前端,有障碍物的放入队尾,遇到障碍物时就要使用拳头了,把能到的范围全扫一遍,每次都取拳最小的,最后的到的vis[h][w]就是就是最少要使用的拳数;
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
int n,h,w;
int vis[505][505];//使用的炸弹数量
//bool v[505][505];
char a[505][505];//被搜索图
int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};
int d1[5]={-2,-1,0,1,2};
struct dd
{
int x;
int y;
int t;
};
void bfs(){
deque<dd> q;
q.push_front({0,0,0});
vis[0][0]=0;
while(!q.empty()){
int x=q.front().x,y=q.front().y,t=q.front().t;
q.pop_front();
for(int i=0;i<4;i++){//不需要打拳的
int xx=x+dx[i],yy=y+dy[i];
if(xx<0||xx>=h||yy<0||yy>=w) continue;
if(a[xx][yy]=='#') continue;
if(vis[xx][yy]<=vis[x][y]) continue;
q.push_front({xx,yy,t});
vis[xx][yy]=t;
}
for(int i=0;i<5;i++){//打拳能到的地方
for(int j=0;j<5;j++){
if((i==0&&j==0)||(i==0&&j==4)||(i==4&&j==4)||(i==4&&j==0)) continue;
int xx=x+d1[i],yy=y+d1[j];//该判断的点
if(xx<0||xx>=h||yy<0||yy>=w) continue;
if(vis[xx][yy]<=vis[x][y]+1) continue;
q.push_back({xx,yy,t+1});
vis[xx][yy]=t+1;
}
}
}
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
cin>>h>>w;
for(int i=0;i<h;i++){
for(int j=0;j<w;j++){
cin>>a[i][j];
}
}
memset(vis,62,sizeof(vis));
bfs();
cout<<vis[h-1][w-1]<<endl;
}
题目:第 k 小
解析:
本题考的是对优先队列的使用,找出第k大的数只需要将前k个小的数放入大顶堆中,堆顶就是第k大的数,需要特别判断的是没有到达k个数的情况。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
int a[200005];
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
int n,m,k;
cin>>n>>m>>k;
priority_queue<int ,vector<int> ,greater<int> >q1;//小顶堆
priority_queue<int ,vector<int> >q2;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
int t=0;
while(q2.size()<k&&t<n) q2.push(a[t++]);
while(t<n) q1.push(a[t++]);
while(m--){
int b;
cin>>b;
if(b==1){
int x;
cin>>x;
int c=q1.top();
int d=q2.top();
if(q2.size()<k){
q2.push(x);
}
else if(x<q2.top()){
q2.push(x);
q2.pop();
q1.push(d);
}
else{
q1.push(x);
}
}
else{
if(q2.size()<k){
cout<<"-1"<<endl;
}
else cout<<q2.top()<<endl;
}
}
return 0;
}
题目:tokitsukaze and Soldier
tokitsukaze and Soldier (nowcoder.com)
解析:
题意是每个士兵都有个战力,同时每个不同的士兵都有希望军队的人数小于s[i]值,所以我们又要选择人数大的士兵,又要战力大。观察到是s[i]小的决定军队人数,所以s[i]我们从大到小将战力拿出来,放入优先队列(小顶堆)自动排序,把超过容量s[i],的踢出,下面容量小的军队用不到踢出。最后取最大。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int, int>
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
priority_queue<int,vector<int>,greater<int> > q1;//小顶堆
int n;
cin>>n;
vector<int> s[100005];
for(int i=0;i<n;i++){
int x,y;
cin>>x>>y;
s[y].push_back(x);
}
int ans=0;int sum=0;
for(int i=n;i>=1;i--){//可以容纳的士兵从大到小
for(int j=0;j<s[i].size();j++){
sum+=s[i][j];
//cout<<s[i][j]<<" ?";
q1.push(s[i][j]);
}
//cout<<endl;
while(q1.size()>i){//容纳量为i将多余的减去,并踢出小顶堆,之后的容量会变小,踢出值不影响
sum-=q1.top();
q1.pop();
}
ans=max(ans,sum);
}
cout<<ans<<endl;
return 0;
}