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 哕哕哕。