CSP-S 模拟 10

CSP-S 模拟 10

T1 二分图匹配

大力分块。

复杂度 \(O(2 n \sqrt{nm} )\)

\(dp[i][j]\) 表示 s1 的第 \(i\) 位匹配 s2 的第 \(j\) 位时,且 i 匹配 j 时,最大匹配数量。

初始化 dp 数组为 \(0\)

但是空间会爆。

又发现 dp 数组当 \(i\) 增加时,其中所有值一定不会下降,一个简单贪心,很好理解,能多匹配尽量多匹配。

于是我们像背包一样,压掉 \(i\) 这一维。

设当前枚举到 s1 的第 \(k\) 位。

转移方程为

\(s2[i]=s1[k]\) 时,

\[dp[i]=\max(dp[i],\max_{0\le j < i}dp[j]+1) \]

注意倒序枚举 \(i\),防止后效性。

现在复杂度为 \(O(nm^2)\)

预处理 \(\max\) 可以做到 \(O(2nm)\)

考虑优化。

发现 dp 数组值最大才到 \(1000\)

又发现,当转移 \(\forall i\)\(s2[i]=s1[k]\)\(\max_{0\le j < i}dp[j]+1\) 值相同时,只在最小的 \(i\) 处转移即可。

贪心即可证明:显然对于所有上述情况中的 \(i\)\(i\) 越小越好,因为 \(i\) 越小,留给 s1 后面的字符的选择空间越大,最终答案就会大。而其他的 \(i\) 就白白浪费了 s2 中 \(i(\min)\)\(i\) 中间的字符,答案一定不优。

显然不同的转移最多只有 \(n\) 次。

我们先开 vector 存每个字符在 s2 中出现位置。

我们需要一个可以支持单点修改,区间查询最大值的东西。

然后我们有两种办法实现转移:

二分套线段树 | 线段树上二分

直接 vector 里二分出第一个 max 改变的位置,转移,不断重复这个过程。

复杂度 \(O(n^2 \log^2 n)\)

代码没写。

分块(下面代码复杂度不正确,改为跳块才正确)

我们对 s2 分块,记录每个区间最大值为 ma1,枚举 s1 的每一位时计算 ma1 的前缀 \(\max\),记进 ma2。

设之前由 \(last\) 这个前缀 \(\max\) 转移而来。
从前往后枚举每个块,若这个块内存在 i 使 \(s2[i]=s1[k]\),并且包含这个块的前缀 \(\max\)\(last\) 不等,则暴力遍历这个块,尝试转移。

简单处理一下即可做到无后效性。

复杂度看似不对。

首先我们需要枚举 s1 的每一位,\(O(n)\)

对于每一位,我们有:
预处理前缀 \(\max\)(ma2)的复杂度 \(O(\frac{m}{B})\)
暴力遍历 \(O(2B)\)。(尝试转移时若无法转移,则下一次尝试时一定可以转移)。
遍历每一块 \(O(\frac{m}{B})\)

总复杂度 \(O(2B+\frac{2m}{B})\)

基本不等式可得复杂度 \(O(2 \sqrt{nm})\)

代码见下面赛时杂糅代码,枚举块改成了在 vector 里二分。

赛时杂糅代码(既有二分,又有分块)

#include<bits/stdc++.h>
#define int long long

using namespace std;

inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';c=getchar())
		x=(x<<1)+(x<<3)+(c^48);
	return f?-x:x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9)  write(x/10);
	putchar(x%10+'0');
}

const int N=1<<20;
int n,m;
char s1[N],s2[N];

vector<int> v[200];
int maxn[N];
int id[N];
const int len=33;
int ma1[N];
int ma2[N];

int solve(char c,int l,int r,int id)
{
    int p=v[c][l];
    int ma=ma2[id-1];
    for(int i=(id-1)*len;i<p;i++) ma=max(ma,maxn[i]);
    int nw=maxn[p];
    
    maxn[p]=ma+1;
    ma1[id]=max(ma1[id],maxn[p]);
    // as=ma;

    int last=ma;
    ma=max(ma,nw);

    for(int i=l+1;i<=r;i++)
    {
        p=v[c][i];
        for(int j=v[c][i-1]+1;j<p;j++) ma=max(ma,maxn[j]);
        
        nw=maxn[p];
        if(ma!=last)
        {
            maxn[p]=ma+1;
            ma1[id]=max(ma1[id],maxn[p]);
            last=ma;
            // as=ma;
        }
        ma=max(ma,nw);
    }

    return last;
}

// void output()
// {
//     for(int i=1;i<=m;i++) cout<<maxn[i]<<" ";
//     // for(int i=1;i<=m;i++) cout<<"i="<<i<<" maxn="<<maxn[i]<<"\n";
//     cout<<"\n";
// }

signed main()
{
    // #ifndef ONLINE_JUDGE
    freopen("match.in","r",stdin);
    freopen("match.out","w",stdout);
    // #endif
    
    cin>>n>>m;
    scanf("%s",s1+1);
    scanf("%s",s2+1);

    for(int i=1;i<=m;i++)
    {
        id[i]=i/len+1;
        v[s2[i]].push_back(i);
    }
    // cout<<s2[98]<<" "<<s2[99]<<" "<<s1[975]<<"\n";//B
    for(int i=1;i<=n;i++)
    {
        // cerr<<"i="<<i<<" ";
        for(int j=1;j<=id[m];j++) 
        ma2[j]=max(ma2[j-1],ma1[j]);
        ma2[id[m]+1]=ma2[id[m]];

        int ma=-1;
        for(int j=0;j<v[s1[i]].size();j++)
        {
            // cerr<<"j="<<j<<" ";
            int p=v[s1[i]][j];
            int nw=ma2[id[p]];
            if(nw==ma)
            {
                // cerr<<"uhfe;oa";
                for(int k=20;k>=0;k--)
                {
                    int to=j+(1<<k);
                    if(to<v[s1[i]].size())
                    {
                        int p_to=v[s1[i]][to];
                        if(ma2[id[p_to]]==ma) j=to;
                    }
                }
                // cerr<<j<<" ";
                continue;
            }
            int l=j,r=j;
            while(j<v[s1[i]].size()-1&&id[v[s1[i]][j]]==id[v[s1[i]][j+1]]) j++;
            r=j;

            int as=solve(s1[i],l,r,id[p]);
            if(as!=ma) ma=as;
            // int pre=ma2[id[p]-1];
        }

        // for(int j=v[s1[i]].size()-1;j>=0;j--)
        // {
        //     int p=v[s1[i]][j];
        //     if(ma2[id[p-1]])
        // }
        // if(maxn[98]==84&&maxn[101]==84) cout<<i<<"\n";
        // if(i!=974&&i!=975) continue;
        // cout<<"i="<<i<<" ma="<<ma<<"\n";
        // output();
        // cout<<"\n";
    }

    int ans=0;
    for(int i=1;i<=m;i++) ans=max(ans,maxn[i]);
    cout<<ans<<"\n";


    return 0;
}

T2 虚图

最短路简单优化。

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar()                                                              \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt)     \
	? EOF                                                                 \
	: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
	int x=0,c=getchar(),f=0;
	for(;c>'9'||c<'0';f=c=='-',c=getchar());
	for(;c>='0'&&c<='9';c=getchar())
		x=(x<<1)+(x<<3)+(c^48);
	return f?-x:x;
}
inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9)  write(x/10);
	putchar(x%10+'0');
}

const int N=2e5+5;
int n,m,t;
vector<int> E[N],V[N];
void add(int u,int v,int w)
{
    E[u].push_back(v);
    V[u].push_back(w);
}
bool vis[N],vis2[N];
int dis[N];
const int MAXN=0x3f3f3f3f3f3f3f3f;
priority_queue<pair<int,int> ,vector<pair<int,int> > ,greater<pair<int,int> > > q;
queue<int> q2;

int dij(int s,int max_len)
{
	while(q2.size())
	{
		int nw=q2.front();
		q2.pop();
		
		vis[nw]=0;
		dis[nw]=MAXN;
	}
	while(q.size()) q.pop();
//    for(int i=1;i<=n;i++) vis[i]=0,dis[i]=MAXN;
    q.push(make_pair(0,s));
    dis[s]=0;
    q2.push(s);

    while(q.size())
    {
        int x=q.top().second;
        q.pop();
        
        if(vis[x]) continue;
        vis[x]=1;
        if(vis2[x]&&x!=s) return dis[x];
        
        for(int i=0;i<E[x].size();i++)
        {
            int to=E[x][i];
            int w=V[x][i];

            if(vis[to]) continue;
            if(dis[x]+w>=max_len) continue;
            if(dis[to]>dis[x]+w)
            {
                dis[to]=dis[x]+w;
                q.push(make_pair(dis[to],to));
                q2.push(to);
            }
        }
	}
    return max_len;
}

signed main()
{
    // #ifndef ONLINE_JUDGE
    freopen("map.in","r",stdin);
    freopen("map.out","w",stdout);
    // #endif

memset(dis,0x3f,sizeof(dis));
    n=read();
    m=read();
    t=read();
    for(int i=1;i<=m;i++)
    {
        int u=read(),v=read(),w=read();
        add(u,v,w);
        add(v,u,w);
    }
    while(t--){
        int x=read();
        vis2[x]=1;
    }

    int ans=MAXN;
    for(int i=1;i<=n;i++)
    if(vis2[i]) ans=min(ans,dij(i,ans));

    cout<<ans;

    return 0;
}


T3 冒泡

T4 亲戚

posted @ 2025-08-14 06:53  Wy_x  阅读(30)  评论(1)    收藏  举报