明日开坑:CF558E A Simple Task 省赛三道补题,AC自动机
今日有意思的题:
0-1迷宫
没太见过dsu这么用的,写起来还算有趣,普及-的难度有些低了,建议升普及/提高-
思路:我们把所有能到的点都合并到一个并查集里,每次询问点直接输出答案即可,期望复杂度是n^2+m级别(1e6)在可接受范围内
#include<bits/stdc++.h>
using namespace std;
const int N = 1e7+100;
int dsu[N],siz[N];
int m[1000+100][1000+100];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};
int n,k;
int tfind(int x)
{
if(dsu[x]==x)
return x;
return dsu[x]=tfind(dsu[x]);
}
void tmerge(int x,int y)
{
x=tfind(x);
y=tfind(y);
if(x!=y)
{
dsu[y]=dsu[x];
siz[x]+=siz[y];
siz[y]=0;
}
}
bool check(int x,int y)
{
if(x>=n||x<0||y>=n||y<0)
return false;
return true;
}
int DFS(int x,int y)
{
if(dsu[x*n+y]!=-1)//记忆化
return tfind(x*n+y);
dsu[x*n+y]=x*n+y;
siz[x*n+y]=1;
for(int i=0;i<=3;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if(check(xx,yy)&&m[xx][yy]!=m[x][y])
{
tmerge(x*n+y,DFS(xx,yy));
}
}
return tfind(x*n+y);
}
int main()
{
cin>>n>>k;
for(int i=0;i<=n*n*4;i++)
{
dsu[i]=-1;
}
char ch;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
cin>>ch;
m[i][j]=ch-'0';
}
}
for(int i=1;i<=k;i++)
{
int x,y;
cin>>x>>y;
int temp=DFS(x-1,y-1);
cout<<siz[temp]<<endl;
}
return 0;
}
题意:给定n个球,他们有自己的速度v和初始位置pos(一维坐标),假设他们碰撞之后交换速度,问经过s秒后他们的位置在哪
思路:
1.球会相互碰撞交换速度,其实碰撞可以想象成两个球互相穿了过去,所以最终得到的坐标和碰撞没有关系,就是每个球的pos+v*s,转化为n个坐标
2.虽然想象中是穿过去的,利用这个原理得到了n个坐标,但是他们并不对应原本的每个球,因为实际上球是没法互相穿过的,也就是说,得到新坐标pos1不对应第一个球
3.既然没法穿过,那么新得到的坐标中最小的肯定对应初始坐标最小的球,新得到的坐标中第二小的肯定对应原始坐标第二小的球,以此类推
ACcode 什么zz题目卡我输出末尾空格啊?!
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N =1e6+100;
int after[N];
int ans[N];
struct node
{
int pos;
int id;
};
node before[N];
bool cmp(node a,node b)
{
if(a.pos==b.pos)
{
return a.id<b.id;
}
return a.pos<b.pos;
}
signed main()
{
int n,s,v;
cin>>n>>s;
for(int i=1;i<=n;i++)
{
cin>>before[i].pos>>v;
before[i].id=i;
after[i]=before[i].pos+v*s;
}
sort(before+1,before+n+1,cmp);
sort(after+1,after+n+1);
for(int i=1;i<=n;i++)
{
ans[before[i].id]=after[i];
}
for(int i=1;i<=n;i++)
{
if(i==n)
cout<<ans[i];
else
cout<<ans[i]<<" ";
}
return 0;
}
题意:给定n天早晚的兔子买卖价格,规定每天只能买一只兔子和卖无限只兔子,在你有初始无限金钱的情况下,请问n天后你最多能赚多少钱
思路:
1.单调栈,但是很难实现
2.从后往前贪心
这样好
1.找出最大值,如果前一天的早晚交易数值中最大值要比目前的最大值小,那么这一天是要在最小值处买一只兔子,然后在最大值处卖掉
2.如果发现前放的早晚值有比目前最大值大的,那么进行最大值的交替
3.最大值交替过程中考虑两种情况,第一种:新的最大值出现在晚上,那么这一天也还要早上买晚上卖
第二种:新的最大值出现在早上,如果晚上的数值比上一个最大值要小,那么也要进行一次买卖
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N =1e6+100;
int rt[N];
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n*2;i++)
cin>>rt[i];
int maxx=0ll;
int ans=0ll;
for(int i=n*2;i>=2;i-=2)
{
int m=rt[i-1];
int a=rt[i];
if(maxx<max(m,a))
{
if(m<a)
ans+=a-m;
else if(maxx>a)
ans+=maxx-a;
maxx=max(m,a);
}
else
ans+=maxx-min(m,a);
}
cout<<ans<<endl;
return 0;
}
I. chino with mates
一眼二分好吧,nlogn不暴力留着过年吗
细节,凡是二分题的边界都非常要命
1.左侧限界要向上取整
2.寻找右侧限界要upper_bound,别忘了你之前是向下取整的
3.还有a[i]等于0的情况
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+100;
int a[N];
int b[N];
signed main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=m;i++)
cin>>b[i];
double l,r;
int ans=0;
int pos1=0,pos2=0;
cin>>l>>r;
sort(b+1,b+m+1);
for(int i=1;i<=n;i++)
{
double ll,rr;
if(a[i]==0)
{
if(l<=0&&r>=0)
ans+=m;
continue;
}
else if(a[i]>0)
{
ll=ceil(l/a[i]*1.0);
rr=floor(r/a[i]*1.0);
}
else
{
ll=ceil(r/a[i]*1.0);
rr=floor(l/a[i]*1.0);
}
pos1=lower_bound(b+1,b+m+1,ll)-b;
pos2=upper_bound(b+1,b+m+1,rr)-b;
ans+=pos2-pos1;
}
cout<<ans<<endl;
return 0;
}
今日无趣的题
G. cocktail with snake
区区签到无趣无趣
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
int t;
for(cin>>t;t;t--)
{
int ans=0ll,n,m,k;
cin>>n>>m>>k;
int r=k/n;
k=k-n*r;
ans+=r;
if(r%2)
ans+=(n-k-1);
else
ans+=k;
cout<<ans<<endl;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+100;
char s[N];
char ans1[N];
char ans2[N];
char sub[N];
int main()
{
int n;
cin>>n;
cin>>s+1;
int l,r,len;
cin>>l>>r>>len;
for(int i=1;i<=n;i++)
ans2[i]=s[i],ans1[i]=s[i];
for(int i=0;i<len;i++)
ans2[r+i]=s[l+i];
for(int i=0;i<len;i++)
ans1[r+i]=ans1[l+i];
for(int i=1;i<=n;i++)
{
cout<<ans1[i];
}
cout<<endl;
for(int i=1;i<=n;i++)
{
cout<<ans2[i];
}
cout<<endl;
return 0;
}