CF1677D-Tokitsukaze and Permutations【结论】

1|0正题

题目链接:https://www.luogu.com.cn/problem/CF1677D


1|1题目大意

对于一个排列pi,定义一个序列v=F(p),其中vi=j=1i1[pj>pi]

一次冒泡排序为依次对1n1进行:若pi>pi+1则交换pi,pi+1

现在给出一个序列v,其中有的位置可以任意填数,求有多少个排列p进行k次冒泡排序后的p满足F(p)=v

1n106,0kn1


1|2解题思路

首先排列pF(p)之间是能一一对应的。

然后我们考虑把p的变化反映到F(p)上。

F(p)=v,那所有会被带着移动的pi都有vi=0,然后被移动过去的每一个前面比他大的个数少一个。也就是v中所有的0都移动到它的下一个0处(如果没有就移动到末尾),然后其余的所有数字减一。

那么也就是原来值在[1,k]范围内的冒泡排序k次后都变为了0,并且如果一个数字原本是i变为了0,那么就代表了有i0从它前面到达了它的后面,反过来说数字的变化可以代表0的移动。

而且我们还能发现一个性质,就是进行了k次冒泡排序后的序列vk个值肯定为0

那么再往前的vi=0的位置在原本就可以是[0,k]之间的任意数字了,而且这也决定了后面0的移动,不需要考虑位置关系。

时间复杂度:O(n)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e6+10,P=998244353; ll T,n,k,a[N]; signed main() { scanf("%lld",&T); while(T--){ scanf("%lld%lld",&n,&k); for(ll i=1;i<=n;i++)scanf("%lld",&a[i]); bool flag=0; for(ll i=n;i>n-k;i--) if(a[i]>0){flag=1;break;} if(flag){puts("0");continue;} ll ans=1; for(ll i=1;i<=n-k;i++) if(a[i]==0)ans=ans*(k+1)%P; else if(a[i]==-1) ans=ans*(i+k)%P; for(ll i=1;i<=k;i++)ans=ans*i%P; printf("%lld\n",ans); } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16341967.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示