动态规划 | 北邮OJ | 94. 最小距离查询

这篇博客介绍了如何使用动态规划和set数据结构解决北邮在线判题系统(OJ)上的94题——最小距离查询。作者通过set大法实现了代码,并成功获得正确答案。文章探讨了状态转移过程,用pre[k]记录字母k最右边的出现位置,以此来优化解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://vpn.bupt.edu.cn/http/10.105.242.80/problem/p/94/
用set大法写了一堆自己都看不懂的代码, 一提交居然AC了, 一发入魂

堪比DP的set大法

#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 510000
#define INF 1000000
#define bug(x) cout<<#x<<"="<<x<<endl;

using namespace std;

char buf[100010];

int main()
{
//    freopen("./in","r",stdin);
    int N;
    scanf("%d",&N);
    while(N--){
        scanf("%s",buf);
        int n;
        scanf("%d",&n);
        int len=strlen(buf);
        set<int> pos[26];   //记录某一字母所在的所有位置
        FF(i,len){
            pos[buf[i]-'a'].insert(i);
        }
        while(n--){
            char op[20];
            char data[20];
            scanf("%s%s",op,data);
            if(strcmp(op,"INSERT")==0){
                buf[len]=data[0];
                pos[buf[len]-'a'].insert(len);//维护
                len++;
                buf[len]=0;
            }else{
                int p;
                int ans;
                sscanf(data,"%d",&p);
                char c=buf[p];
                set<int>& tpos=pos[c-'a'];
                set<int>::iterator it=tpos.find(p);
                if(it==tpos.end()){     //找不到
                    ans=-1;
                }
                else if(tpos.size()==1){   //只记录了找到的一个
                    ans=-1;
                }
                else{
                    it++;
                    ans=INF;
                    if(it!=tpos.end()){
                        ans=*it-p;
                    }
                    it--;//复原
                    if(it!=tpos.begin()){
                        it--;
                        if( (p-*it)<ans){
                            ans=(p-*it);
                        }
                    }
                }
                printf("%d\n",ans);
            }
        }

    }
    return 0;
}

动态规划

其实DP也简单.
对于录入的数据, 从左到有做如下状态转移:

  1. 用pre[k] 记录 字母k最近(最靠右)出现的下标. 未出现用0代替
  2. 对字符串从左到右扫描, 当前下标为i , 字符为k, 做判断 :
  • 如果pre[k]首次出现
pre[k] = i;		//仅仅做更新
  • 如果pre[k]不是首次出现
j=pre[k]		//记录上次位置
pre[k] = i;		//做更新
f[i]=i-j;		//因为i是最近(右)出现的, 必然距离左边的那个字母最近
f[j]=min(f[j],f[i])	//而左边的, 需要状态转移

欧阳巨佬代码:

// #include <bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
#include<deque>
#include<cmath>
#include<set>
#include<cstring>
#include<string.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
//----------------
#define int long long
#define double long double
//----------------
#define file(s) freopen(s ".in", "r", stdin), freopen(s ".out", "w", stdout)
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
#define sdf(x) x=read()
#define For(i, a, b) for (int i = (a); i <= (b); i++)
#define FFor(i, a, b) for (int i = (a); i >= (b); i--)
#define me(a, b) memset(a, b, sizeof(a))
#define addmod(x, y) (x) = ((x)+ (y)) % mod
#define mulmod(x, y) (x) = (((x) % mod) * ((y) % mod)) % mod
#define chkmin(x, y) (x) = (x) <= (y) ? (x) : (y)
#define chkmax(x, y) (x) = (x) >= (y) ? (x) : (y)
#define mid ((l + ((r - l)/2)))
#define Edge struct edge{int to, nx, w;}e[N << 1];int fi[N];int ce = 1;
#define star_link inline void add(int u, int v, int w){e[++ce] = (edge){v, fi[u], w};fi[u] = ce;}
#define Qmul inline ll qmul(ll x,ll y){ll ans=1;for(;y;y>>=1,mulmod(x,x))if(y&1)mulmod(ans,x);return ans;}
#define Go(u) for (int i = fi[u]; i; i = e[i].nx)
#define random(a, b) ((a) + rand() % ((b) - (a) + 1))
#define cnm cout<<"d"
#define bg1(x) cout<<(#x)<<":"<<(x)<<" "<<endl
#define bg2(x,y) cout<<(#x)<<":"<<(x)<<" "<<(#y)<<":"<<(y)<<" "<<endl
#define bg3(x,y,z) cout<<(#x)<<":"<<(x)<<" "<<(#y)<<":"<<(y)<<" "<<(#z)<<":"<<(z)<<" "<<endl
#define bg4(x,y,z,w) cout<<(#x)<<":"<<(x)<<" "<<(#y)<<":"<<(y)<<" "<<(#z)<<":"<<(z)<<" "<<(#w)<<":"<<(w)<<" "<<endl
#define bg5(x,y,z,w,k) cout<<(#x)<<":"<<(x)<<" "<<(#y)<<":"<<(y)<<" "<<(#z)<<":"<<(z)<<" "<<(#w)<<":"<<(w)<<" "<<(#k)<<":"<<(k)<<" "<<endl
int die = 0;
#define Die die++;if(die>100000){cout<<"dead!!!";exit(0);}
#define lson p << 1, l, mid
#define rson p << 1 | 1, mid + 1, r
#define root 1, 1, n
const double eps = 1e-9;
// srand((unsigned)time(NULL));
ll mod = 1e9 + 7;
const int N = 1e6 + 5;

int T;
char s[N], ss[N];
int q;
char c;
int n;
int f[N];
int pre[N];

void wk(int i) {
    f[i] = inf;
    int k=s[i] - 'a';
    int j = pre[k];
    if (!pre[k])
        pre[k] = i;
    else {
        f[i] = i - j;
        pre[k] = i;
        f[j]=min(f[j],i-j);
    }
}


void wk2(int i) {    //这个是我阅读巨佬代码后做的优化, 减少代码量, 逻辑与wk等效
    f[i] = inf;
    int k=s[i] - 'a';
    int j = pre[k];
    if(pre[k]) {
        f[i] = i - j;
        f[j]=min(f[j],i-j);
    }
    pre[k] = i;
}


signed main()
{
    freopen("in","r",stdin);
    sdf(T);
    while (T--) {
        scanf("%s", s + 1);
        n = strlen(s + 1);
        sdf(q);
        For(i, 0, 25)pre[i] = 0;
        For(i, 1, n) {
            wk(i);
        }
        while (q--) {
            scanf("%s", ss + 1);
            if (ss[1] == 'I') {
                scanf(" %c", &c);
                s[++n] = c;
                wk(n);
            } else {
                int x;
                sdf(x);
                x++;
                if (f[x] == inf)printf("-1\n");
                else printf("%lld\n", f[x]);
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值