4.16学习记录

这篇博客探讨了在编程竞赛中如何使用AC自动机解决字符串问题,并展示了其在0-1迷宫、球的速度交换和兔子买卖价格等场景中的应用。作者还分享了在处理这些问题时的思路和代码实现,包括并查集、单调栈和二分查找等数据结构的巧妙运用。
摘要由CSDN通过智能技术生成

明日开坑: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;
}

F. chino with ball

题意:给定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;
}

E. is the order a rabbit ??

题意:给定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;
}

K. chino with c language

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值