• Codeforces Round #778 (Div. 1 + Div. 2)


    F. Minimal String Xoration

    题目描述

    点此看题

    解法

    \(f(s,d)\)\(t_i=s_{i\oplus d}\) 的字符串 \(t\),可以将问题转化成:把 \(f(s,0),f(s,1)...f(s,2^n-1)\) 按照字典序从小到大排序,那么字典序最小的就是答案。

    那么可以考虑类似后缀数组一样倍增,假设现在我们知道在 \(2^k\) 的前缀意义下,\(f(s,0\sim2^{n}-1)\) 的大小关系,我们考虑快速计算在 \(2^{k+1}\) 的前缀意义下 \(f(s,0\sim 2^{n}-1)\) 的大小关系。

    \(rk[i]\) 表示 \(f(s,i)\) 的字典序排名,那么 \(f(s,i)\) 的特征可以用 \((rk[i],rk[i\oplus 2^k])\) 来表示,我们把这个二元组排序,然后生成新一轮的 \(rk\) 即可(思路本质上就是后缀数组的思路),时间复杂度 \(O(n^22^n)\)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int M = 1<<18;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,b[26],rk[M],sa[M],nw[M];char s[M];
    signed main()
    {
    	n=1<<read();scanf("%s",s);
    	for(int i=0;i<n;i++) b[s[i]-'a']++;
    	for(int i=1;i<26;i++) b[i]+=b[i-1];
    	for(int i=0;i<n;i++) rk[i]=b[s[i]-'a'];
    	for(int w=1;w<n;w<<=1)
    	{
    		for(int i=0;i<n;i++) sa[i]=i;
    		sort(sa,sa+n,[&](int i,int j)
    		{return rk[i]==rk[j]?rk[i^w]<rk[j^w]:rk[i]<rk[j];});
    		nw[sa[0]]=1;int num=1;
    		for(int i=1;i<n;i++)
    			nw[sa[i]]=(rk[sa[i]]==rk[sa[i-1]]
    			&& rk[sa[i]^w]==rk[sa[i-1]^w])?num:++num;
    		memcpy(rk,nw,sizeof rk);
    	}
    	for(int i=0;i<n;i++)
    		printf("%c",s[i^sa[0]]);
    	puts("");
    }
    

    G. Snowy Mountain

    题目描述

    点此看题

    解法

    比较离谱的一点是,我照着标程抄,结果把代码长度、空间、时间都变小了

    考虑如果只能走下坡路的话,那么点 \(u\) 的最远滑行距离就是 \(h_u\),现在把平滑考虑进来,我们称周围存在 \(h_u=h_v\) 的点 \(u\) 为平滑点。如果我们在平滑点 \(x\) 滑行,那么滑行距离就是 \(2\cdot h_u-h_x\)(因为会损耗 \(h_x\) 的动能),所以问题转化成,我们需要对每个点 \(u\) 找到可以到达并且 \(h_x\) 最小的滑行点 \(x\)

    一个关键的 \(\tt observation\) 是:\(h_x\) 不同的滑行点 \(x\) 至多只有 \(O(\sqrt n)\) 种,这是因为构造出一个滑行点 \(x\) 至少需要多划分 \(h_x\) 个点(要把路径复刻一遍),那么我们就有 \(\sum h_x\leq n\)

    所以对于每种 \(h_x\) 单独处理,可以按照 \(h_u\) 的大小把所有点 \(u\) 分层,那么同层移动增加 \(1\) 的势能,向更低层移动减少 \(1\) 的势能。只能保留大于等于 \(0\) 的势能(这样才能保证可达性),如果最后势能 \(=0\) 那么就说明可以到这个平滑点。设 \(c(u,i)\) 表示从 \(u\)\(h_x=i\)\(x\) 的最小势能,按照层从小到大转移即可,时间复杂度 \(O(n\sqrt n)\)

    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <queue>
    using namespace std;
    const int M = 200005;
    const int inf = 0x3f3f3f3f;
    #define pb push_back
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,d[M],a[M],b[M],vis[M];
    vector<int> g[M],f[M],c[M];queue<int> q;
    void upd(int &x,int y) {x=min(x,y);}
    void dfs1(int u,int fa)
    {
    	vis[u]=1;
    	for(int v:g[u]) if((v^fa) && d[u]==d[v])
    	{
    		dfs1(v,u);c[u][b[d[u]]]=1;
    		for(int i=1;i<=m;i++)
    			upd(c[u][i],c[v][i]+1);
    	}
    }
    void dfs2(int u,int fa)
    {
    	for(int v:g[u]) if((v^fa) && d[u]==d[v])
    	{
    		c[v][b[d[v]]]=1;
    		for(int i=1;i<=m;i++)
    			upd(c[v][i],c[u][i]+1);
    		dfs2(v,u);
    	}
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)
    		read()?q.push(i),0:d[i]=inf;
    	for(int i=1;i<n;i++)
    	{
    		int u=read(),v=read();
    		g[u].pb(v);g[v].pb(u);
    	}
    	//bfs
    	while(!q.empty())
    	{
    		int u=q.front();q.pop();
    		for(int v:g[u])
    		{
    			if(d[v]>d[u]+1)
    				d[v]=d[u]+1,q.push(v);
    		}
    	}
    	//flippable
    	for(int u=1;u<=n;u++) for(int v:g[u])
    		if(d[u]==d[v] && !b[d[u]])
    			a[++m]=d[u],b[d[u]]=m;
    	for(int i=1;i<=n;i++)
    		c[i].resize(m+1),f[d[i]].pb(i);
    	//layer
    	for(int w=0;w<=n;w++)
    	{
    		for(auto u:f[w])
    		{
    			for(int i=1;i<=m;i++) c[u][i]=inf;
    			for(int v:g[u]) if(d[v]==d[u]-1)
    				for(int i=1;i<=m;i++)
    					upd(c[u][i],max(0,c[v][i]-1));
    		}
    		for(auto u:f[w]) if(!vis[u])
    			dfs1(u,0),dfs2(u,0);
    	}
    	for(int u=1;u<=n;u++)
    	{
    		int ans=d[u];
    		for(int i=1;i<=m;i++) if(!c[u][i])
    			ans=max(ans,2*d[u]-a[i]);
    		printf("%d ",ans);
    	}
    	puts("");
    }
    
  • 相关阅读:
    第一章 教育观
    教资时间及考试分布情况
    第二章 信号量及条件变量(三)——> 重点
    Apache ftpServer 配置用户
    下载谷歌拼音输入法离线包
    springboot 启动脚本优化
    Json序列化和反序列化注意点-无参构造器
    Springboot2使用redis提示无法注入redisTemplate
    【转】iOS 保持界面流畅的技巧
    Java文件操作相关
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/16036528.html
Copyright © 2020-2023  润新知