0223模拟赛(波鱼)

happysugarlife / 「PJudge#1」 删数

题意

\(~~~~\) 删除一个数的条件:为两边数的等差中项。求最后能最少剩多少数。
\(~~~~\) \(1\leq n\leq 10^6,1\leq a_i\leq 10^9\).

题解

\(~~~~\) 注意到删除过后那两边的数的差就会 \(\times 2\),故把原数列差分过后把每个差分的数记作 \(x\times 2^y\) ,其中 \(x\) 为一个奇数 (或者 \(0\)) ,那么我们考虑可不可以把 \(x\) 相同的连续段拉出来一起做。

\(~~~~\) 那么直接在每段上 \(dp_{i,j}\) 表示第 \(i\) 个位置上的数,后面系数为 \(2^j\) 一路合并最前面到哪里,那么就可以dp出转移点,两个转移点之间必然有一个数剩下来阻隔。

\(~~~~\) 时间复杂度:\(\mathcal{O(n \log n)}\).

\(~~~~\) 考场正解:随便乱贪,无所谓,数据会出手。

代码
查看代码
#include <bits/stdc++.h>
using namespace std;
void read(int &x)
{
	x=0;int Sig=1;char c=getchar();
	while(!('0'<=c&&c<='9')){if(c=='-')Sig=-1;c=getchar();}
	while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
	x*=Sig;
}
int dp[1000005],arr[1000005];
int p[1000005],q[1000005],f[1000005][31];
int Solve(int l,int r)
{
	if(!p[l]) return 1;
	f[l][q[l]]=l-1;
	for(int i=l+1;i<=r;i++)
	{
		int M=q[i],pos=i-1;
		while("I am an idiot.")
		{
			f[i][M]=pos;
			if(pos<l||(!(~f[pos][M]))) break;
			pos=f[pos][M]; M++;
		}
	}
	dp[l-1]=0;
	for(int i=l;i<=r;i++)
	{
		for(int j=0;j<=30;j++) if(~f[i][j]) dp[i]=min(dp[i],dp[f[i][j]]+1);
	}
	return dp[r];
}
int main() {
//	freopen("sugar.in","r",stdin);
//	freopen("sugar.out","w",stdout);
	int T,n,Ans=1;T=1;
	while(T--)
	{
		read(n); Ans=1;
		for(int i=0;i<=n;i++) dp[i]=1e9,p[i]=q[i]=0;
		for(int i=0;i<=n;i++) for(int j=0;j<=30;j++) f[i][j]=-1;
		for(int i=1;i<=n;i++) read(arr[i]);
		for(int i=1;i<n;i++)
		{
			p[i]=arr[i+1]-arr[i];
			while((!(p[i]&1))&&p[i]) p[i]>>=1,q[i]++;
		}
		for(int l=1,r=1;l<n;l=r+1)
		{
			r=l;
			while(r<n-1&&p[l]==p[r+1]) r++;
			Ans+=Solve(l,r);
		}
		printf("%d\n",Ans);	
	}
	return 0;
}
/*
出题人你会不会给部分分啊,区间DP都不给一个????? 
五套题有三套不会给部分分,一套给虚空部分分
我只能流汗黄豆
 
注意到所有极大等差段的两端总是会保留的
所以我们只需要对每个极大等差段分别求答案
然后加起来
对每个等差段:
dp_i=dp_{\lceil i/2 \rceil} + (i is even) 
就好了? 
1 3 5 9
叉掉 
不要太荒谬 
删一次这一段的公差*2 
所有公差都写作 2^k*x,x为奇数 
实际上x相同的一堆连续公差应该放一起算 
But How?
对每段每个位置预处理最左某个幂次可以到哪里
合并起来
那么dp的时候就以该幂次可合并的最大段为转移位置来。
*/

starwearer

题意

\(~~~~\) 求长为 \(n\) ,有 \(k\) 个逆序对且排列内置换长度在 \(2\) 以内的排列数量的奇偶性。
\(~~~~\) \(1\leq n\leq 4000,1\leq k\leq \frac{k(k-1)}{2}\).

题解

\(~~~~\) 对于排列 \(p\) ,记 \(q_{p_i}=i\) 的排列 \(q\)\(p\) 的逆。

\(~~~~\) 我们注意到存在置换长度大于 \(2\) 的排列的逆一定与自己不一样,反之一定与自己一样。所以置换长度大于 \(2\) 的排列对方案数的奇偶性没有影响,因为每个排列必然有逆来抵消。

\(~~~~\) 朴素 \(dp\) 加上前缀和优化可以做到 \(\mathcal{O(n^3)}\)

\(~~~~\) dp状态是 bool 类型的也太浪费了吧,这不得开一个 bitset?那么前缀和就变成按位异或了,时间复杂度变为 \(\mathcal{O(\frac{n^3}{\omega})}\)

代码
查看代码
#include <bits/stdc++.h>
using namespace std;
int n,k;
bitset<8000010> Bit;
int solve(int x,int y)
{
	if(!x||!y) return 1;
	if(__builtin_clz(x)==__builtin_clz(y)) return 0;
	if(31-__builtin_clz(x)>31-__builtin_clz(y)) return solve(x-(1<<(31-__builtin_clz(x))),y);
	else return solve(x,y-(1<<(31-__builtin_clz(y))));
}
int main() {
//	freopen("starwearer.in","r",stdin);
//	freopen("starwearer.out","w",stdout);
	scanf("%d %d",&n,&k);
	for(int i=0;i<=k;i++) Bit[i]=solve(n-1,i);
	for(int i=1;i<=n;i++) Bit^=(Bit<<i);
	printf("%d",(int)Bit[k]);
	return 0;
}

ANIME_19

\(~~~~\) 这道题出题人说卖给lxl了,所以就不写了力。


格蕾家今天的饭

\(~~~~\) 关键词:凸包暴力 复杂度是对的

\(~~~~\) 敢写就敢过的题放 T4 哕哕哕。

posted @ 2023-02-24 21:22  Azazеl  阅读(32)  评论(0编辑  收藏  举报