题解 礼物

传送门
CF718E Matvey's Birthday

首先发现直径 \(\leqslant 15\)
于是有个 \(O(15\frac{n^2}{w})\) 的做法是对每个点维护走 \(j\) 步能到达的点集

然后正解:
发现走法也就那么几种:一个一个走或者用中转颜色跳一下
于是令 \(f_{i, j}\) 为从 i 走到颜色为 j 的点的最短路径
\(g_{i, j}\) 为从颜色 i 走到颜色 j 的最短路径
对于两个点 \(i, j\),有 \(dis(i, j)=\min(|i-j|, f_{i, c}+f_{j, c}+1)\)
后面那个东西仍然枚举不起,然而我们发现不同的 \(f_{i, c},f_{j, c}\) 组合一共没有几种
具体地,有 \(g_{s_i, c}\leqslant f_{i, c}\leqslant g_{s_i, c}+1\)
于是可以状压预处理出 \((82^8)^2\) 种组合
然后对每个 \(i\) 枚举它前面 15 个爆扫,更远的就枚举状态就好了

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define fir first
#define sec second
#define ll long long
//#define int long long

int n;
char s[N];

#if 0
namespace force{
	bool vis[N];
	int head[N], dis[N], ecnt;
	priority_queue<pair<int, int>> q;
	struct edge{int to, next;}e[N<<1];
	inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}
	void dij(int s) {
		memset(vis, 0, sizeof(vis));
		memset(dis, 127, sizeof(dis));
		dis[s]=0;
		q.push({0, s});
		while (q.size()) {
			pair<int, int> u=q.top(); q.pop();
			if (vis[u.sec]) continue;
			vis[u.sec]=1;
			for (int i=head[u.sec],v; ~i; i=e[i].next) {
				v = e[i].to;
				if (dis[u.sec]+1<dis[v]) {
					dis[v]=dis[u.sec]+1;
					q.push({-dis[v], v});
				}
			}
		}
	}
	void solve() {
		memset(head, -1, sizeof(head));
		for (int i=1; i<=n; ++i) {
			for (int j=1; j<=n; ++j) if (i!=j) {
				if (abs(i-j)==1 || s[i]==s[j]) add(i, j);
			}
		}
		ll ans1=0, ans2=0;
		for (int i=1; i<=n; ++i) {
			dij(i);
			int maxn=0, cnt=0;
			for (int j=1; j<=n; ++j) maxn=max(maxn, dis[j]);
			for (int j=1; j<=n; ++j) if (maxn==dis[j]) ++cnt;
			if (maxn>ans1) ans1=maxn, ans2=cnt;
			else if (maxn==ans1) ans2+=cnt;
		}
		assert(!(ans2&1));
		cout<<ans1<<' '<<ans2/2<<endl;
	}
}
#endif

namespace task1{
	bitset<5010> f[5010][17], st[17];
	void solve() {
		//cout<<double(sizeof(f)+sizeof(st))/1000/1000<<endl;
		for (int i=1; i<=n; ++i) f[i][0][i]=1, st[s[i]-'a'][i]=1;
		int j;
		for (j=1; ; ++j) {
			bool any=0;
			for (int i=1; i<=n; ++i) {
				f[i][j]|=f[i][j-1]|f[i-1][j-1]|f[i+1][j-1]|st[s[i]-'a'];
				if (f[i][j].count()!=n) any=1;
			}
			for (int i=1; i<=n; ++i) st[s[i]-'a']|=f[i][j];
			if (!any) break;
		}
		ll ans=0;
		for (int i=1; i<=n; ++i) ans+=n-f[i][j-1].count();
		assert(!(ans&1));
		cout<<j<<' '<<ans/2<<endl;
	}
}

namespace task{
	ll cnt;
	pair<int, int> st[N];
	int f[N][8], g[8][8], h[8][1<<8][8][1<<8], mp[8][1<<8], maxn;
	void solve() {
		memset(f, 0x3f, sizeof(f));
		memset(g, 0x3f, sizeof(g));
		memset(h, 0x3f, sizeof(h));
		for (int i=1; i<=n; ++i) s[i]-='a';
		for (int i=0; i<8; ++i) g[i][i]=0;
		for (int i=1; i<=n; ++i)
			for (int j=max(1, i-15); j<=min(n, i+15); ++j) {
				f[i][s[j]]=min(f[i][s[j]], abs(i-j));
				g[s[i]][s[j]]=min(g[s[i]][s[j]], abs(i-j));
				g[s[j]][s[i]]=min(g[s[j]][s[i]], abs(i-j));
			}
		for (int k=0; k<8; ++k)
			for (int i=0; i<8; ++i)
				for (int j=0; j<8; ++j)
					g[i][j]=min(g[i][j], g[i][k]+g[k][j]+1);
		for (int i=1; i<=n; ++i)
			for (int j=0; j<8; ++j)
				for (int k=0; k<8; ++k)
					f[i][k]=min(f[i][k], f[i][j]+g[j][k]+1);
		#if 0
		cout<<"---f---"<<endl;
		for (int i=1; i<=n; ++i) {for (int j=0; j<8; ++j) cout<<setw(5)<<f[i][j]<<' '; cout<<endl;}
		cout<<"---g---"<<endl;
		for (int i=0; i<8; ++i) {for (int j=0; j<8; ++j) cout<<setw(5)<<g[i][j]<<' '; cout<<endl;}
		#endif
		for (int i=0; i<8; ++i)
			for (int s=0; s<(1<<8); ++s)
				for (int j=0; j<8; ++j)
					for (int t=0; t<(1<<8); ++t)
						for (int k=0; k<8; ++k)
							h[i][s][j][t]=min(h[i][s][j][t], g[i][k]+bool(s&(1<<k))+g[j][k]+bool(t&(1<<k))+1);
		for (int i=1; i<=n; ++i) {
			st[i].fir=s[i];
			for (int j=0; j<8; ++j)
				if (f[i][j]==g[s[i]][j]+1) st[i].sec|=1<<j;
		}
		for (int i=1; i<=n; ++i) {
			for (int j=max(1, i-15); j<i; ++j) {
				int len=min(i-j, h[st[i].fir][st[i].sec][st[j].fir][st[j].sec]);
				//cout<<"ij: "<<i<<' '<<j<<' '<<len<<endl;
				if (len>maxn) maxn=len, cnt=1;
				else if (len==maxn) ++cnt;
			}
			for (int j=0; j<8; ++j)
				for (int t=0; t<(1<<8); ++t) if (mp[j][t]) {
					int len=h[st[i].fir][st[i].sec][j][t];
					if (len>maxn) maxn=len, cnt=mp[j][t];
					else if (len==maxn) cnt+=mp[j][t];
				}
			if (i>15) ++mp[st[i-15].fir][st[i-15].sec];
		}
		cout<<maxn<<' '<<cnt<<endl;
	}
}

signed main()
{
	freopen("gift.in", "r", stdin);
	freopen("gift.out", "w", stdout);

	scanf("%d%s", &n, s+1);
	//force::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-02-24 20:21  Administrator-09  阅读(1)  评论(0编辑  收藏  举报