StarSilk 题单笔记-2600

Link


Three Days Grace

如果想到一个很复杂/正确性可疑的贪心,那就应该考虑一下 DP 了。

一个经典套路是递减枚举最小值,维护最小化的最大值,就是双指针。

考虑 \(dp_i\) 是数 \(i\) 在当前最小值约束下拆分后最小化的最大值。

首先,当最小值从 \(x+1 \to x\) 时,只有 \(x\) 的倍数 \(dp\) 值可能会被更新。

更具体地说,此时我们需要处理的是如下的转移:

if (y>=x*x) dp[y]=min(dp[y],dp[y/x]);

显然这样的转移个数是调和级数的。

答案就是对每个 \(x \leq \min a\) 处的 \(\min dp - x\)\(\min\)

怎么求 \(\min dp\) 呢?

我们对 \(a\) 中数对应的 \(dp\) 值打上 tag,每次转移时如果影响到 \(a\) 中的数就挪一下 tag,并把右指针左移到第一个有 tag 的位置就好。(利用双指针的单调性)

Code
void R()
{
	int n,m,mn,mx,ans=1e9;
	cin>>n>>m;
	mx=m;
	vector<int> a(n),dp(m+1),vis(m+1),fl(m+1);
	iota(dp.begin(),dp.end(),0);
	for (int &x:a)
	{
		cin>>x;
		fl[x]=vis[x]=1;
	}
	mn=*min_element(a.begin(),a.end());
	for (int i=m;i>=1;i--)
	{
		for (i64 j=1ll*i*i;j<=m;j+=i)
		{
			if (vis[j]) fl[dp[j]]--;
			dp[j]=min(dp[j],dp[j/i]);
			if (vis[j]) fl[dp[j]]++;
		}
		while (!fl[mx]) mx--;
		if (i<=mn) ans=min(ans,mx-i);
	}
	cout<<ans<<'\n';
	return;
}

i*i 可能爆 int,切记切记。


Latin Square

我们可以把矩阵 \(a\) 看成 \(\mathcal{O}(n^2)\) 个三元组信息:\(( i,j,a_{i,j} )\),于是各个操作分别变成加减某维或交换某维。

于是我们 \(\mathcal{O}(m)\) 模拟操作,记录下三维在操作后是谁,然后 \(\mathcal{O}(n^2)\) 还原即可。

感觉实现还是很有趣的
void R()
{
	int n,m;
	string s;
	cin>>n>>m;
	vector<vector<int>> mat(n,vector<int>(n)),opt(mat);
	for (int i=0;i<n;i++)
		for (int j=0;j<n;j++)
		{
			cin>>mat[i][j];
			mat[i][j]--;
		}
	cin>>s;

	array<int,3> from={0,1,2},val={0,0,0};
	for (int i=0;i<m;i++)
	{
		if (s[i]=='U') val[0]--;
		else if (s[i]=='D') val[0]++;
		else if (s[i]=='L') val[1]--;
		else if (s[i]=='R') val[1]++;
		else if (s[i]=='I')
		{
			swap(from[1],from[2]);
			swap(val[1],val[2]);
		}
		else
		{
			swap(from[0],from[2]);
			swap(val[0],val[2]);
		}
	}

	for (int i=0;i<n;i++)
		for (int j=0;j<n;j++)
		{
			auto solve=[&](int op)->int
			{
				if (op==0) return i;
				if (op==1) return j;
				return mat[i][j];
			};

			auto get=[&](int id)->int
			{
				return ((solve(from[id])+val[id])%n+n)%n;
			};

			opt[get(0)][get(1)]=get(2);
		}
		
	for (int i=0;i<n;i++)
	{
		for (int j=0;j<n;j++)
		{
			cout<<opt[i][j]+1;
			if (j+1!=n) cout<<' ';
		}
		cout<<'\n';
	}
	cout<<'\n';
	return;
}
posted @ 2024-11-20 20:01  jzcrq  阅读(325)  评论(0)    收藏  举报