首页 > 其他分享 >CSP 模拟 4

CSP 模拟 4

时间:2023-07-24 18:11:07浏览次数:45  
标签:cnt int sum lst 序列 CSP 模拟 define

今日推歌:

  1. Serenade in G ‘Eine kleine Nachtmusik’ K525 - Wolfgang Amadeus Mozart

今天比赛直接搬的 ARC 125,126 的 CD 题,那这样我也能出模拟赛(

但是为什么 HZOI2022 都不写比赛题解,差评

今天被 HZOI2023,2024 薄纱,我直接退役得了

T1 最长上升子序列

考虑一个明显字典序不是最小但是满足条件的构造:

\[(a_1,a_1-1,\cdots,1),(a_2,a_2-1,\cdots,a_1+1),\cdots,(n,n-1,\cdots,a_{n-1}+1) \]

每一组只会向后一组贡献 \(1\) 的最长上升子序列长度,但是这个字典序明显不是最小的,但是可以根据这种构造改进。

构造步骤为:

  1. 一开始将 \([1,a_1)\) 加入集合 \(B\)。
  2. 将 \(a_i\) 加入构造的序列。
  3. 取出当前集合 \(B\) 中的最小数字加入序列,如果没有则不加入。
  4. 将 \((a_i,a_{i+1})\) 加入集合 \(B\)。
  5. 重复 \(2\sim4\) 步直到 \(i=k\)。
  6. 将 \([a_k,n]\) 加入集合 \(B\)。
  7. 将集合 \(B\) 中的元素倒序加入序列。

因为是每次取 \(B\) 中最小的数,所以能保证字典序最小,对于 \(a_i\) 到 \(a_{i+1}\) 的每一个数因为是倒序的,一共有 \(k\) 组这样的数,所以能保证最长上升子序列长度为 \(k\)。

点击查看代码
#include<bits/stdc++.h>
#define N 200005
using namespace std;

int n,k,a[N],b[N],tot,now,num[N];

int main(){
    cin>>n>>k;
    for(int i=1;i<=k;i++)
        scanf("%d",a+i);
    for(int i=1;i<a[1];i++) b[++tot]=i;
    now=1;
    for(int i=1;i<k;i++){
        if(now<=tot) num[i]=b[now++];
        for(int j=a[i]+1;j<a[i+1];j++) b[++tot]=j;
    }
    for(int i=1;i<k;i++){
        printf("%d ",a[i]);
        if(num[i]) printf("%d ",num[i]);
    }
    for(int i=n;i>=a[k];i--)
        printf("%d ",i);
    for(int i=tot;i>=now;i--)
        printf("%d ",b[i]);
}

T2 独特序列

定义 dp 状态 \(f_{i}\) 为以 \(i\) 为结尾的独特序列个数,考虑转移。

设 \(lst_i\) 为上一次出现数 \(i\) 的地方,则 \(a_i\) 的转移不能到 \(lst_{a_i}\) 及之前,因为这样的话就会有并不独特的序列更新,而且在 \(a_i\) 更新之后,\(lst_{a_i}\) 不再产生贡献,因为只需要最后一个用来转移即可,所以转移方程如下:

\[f_i=\sum_{j=lst_{a_i}+1}^{a_i-1}f_j \]

因为要消去影响,所以每次转移之后 \(f_{lst_{a_i}}=0\)。

如果直接转移的话复杂度是 \(O(n^2)\) 的,然后发现转移方程可以用树状数组维护,时间复杂度减为 \(O(n\log n)\)

点击查看代码
#include<bits/stdc++.h>
#define N 200005
#define int long long
using namespace std;

const int p=998244353;
int n,a[N],f[N],lst[N],ans;
struct FenwickTree{
    int c[N];
    int lowbit(int x){return x&(-x);}
    void update(int x,int val){if(!x) return; for(int i=x;i<=n;i+=lowbit(i)) c[i]=(c[i]+val+p)%p;}
    int query(int x){int ans=0;for(int i=x;i;i-=lowbit(i)) ans=(ans+c[i])%p;return ans;}
}T;

signed main(){
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%lld",a+i);
    for(int i=1;i<=n;i++){
        if(!lst[a[i]]) f[i]=1;
        f[i]=(f[i]+(T.query(i-1)-T.query(max(0ll,lst[a[i]]-1))+p)%p)%p;
        T.update(i,f[i]);T.update(lst[a[i]],-f[lst[a[i]]]);lst[a[i]]=i;
    }
    for(int i=1;i<=n;i++)
        ans=(ans+f[lst[i]])%p;
    cout<<ans;
}

T3 最大GCD

如果能把数列的所有数补到最大值的话,则说明直接向上加即可,直接输出。

如果这样的话说明 \(\gcd(a_1,a_2,\cdots,a_n)\le \max a_i\)。

如果想让数列的 \(\gcd\) 被 \(x\) 整除的话,说明数列的每一项都被 \(x\) 整除,所以其最小操作次数为:

\[\sum_{i=1}^{n}x-(a_i\bmod x) \]

如果这个次数 \(\le k\) 的话,说明 \(x\) 是满足条件的 \(\gcd\)。

但是答案并没有单调性,考虑展开这个式子:

\[\begin{aligned} \sum_{i=1}^{n}x-(a_i\bmod x)&=nx-\sum_{i=1}^{n}(a_i\bmod x)\\ &=nx-\sum_{i=1}^{\max a_i}(i\bmod x)cnt_i \end{aligned} \]

其中 \(cnt_i\) 为数 \(i\) 出现的次数,后面的 \((i\bmod x)\) 是以 \(x\) 为周期的,所以考虑维护一个 \(\displaystyle f_n = \sum_{i=1}^{n} i\cdot cnt_i\) 和一个 \(\displaystyle g_n = \sum_{i=1}^{n} cnt_i\),然后对于每个 \(((k-1)x,kx]\) 来说它的贡献为 \(kx\cdot (g_{kx}-g_{(k-1)x})-(f_{kx}-f_{(k-1)x})\) 求解即可,时间复杂度为 \(O(nH_n)=O(n\log n)\)。

点击查看代码
#include<bits/stdc++.h>
#define N 600005
#define int long long
using namespace std;

int n,k,a[N],Gcd,maxn,sum,cnt[N],f[N],g[N];

signed main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++)
        scanf("%lld",a+i),maxn=max(a[i],maxn),cnt[a[i]]++;
    for(int i=1;i<=N-5;i++) f[i]=f[i-1]+cnt[i],g[i]=g[i-1]+cnt[i]*i;
    for(int i=1;i<=n;i++) sum+=maxn-a[i];
    if(sum<=k){
        cout<<maxn+(k-sum)/n;
        return 0;
    }
    for(int i=maxn;i>=1;i--){
        int tmp=0;
        for(int j=1;(j-1)*i<=maxn;j++)
            tmp+=(f[i*j-1]-f[i*(j-1)])*i*j-(g[i*j-1]-g[i*(j-1)]);
        if(tmp<=k){
            printf("%lld\n",i);
            return 0;
        }
    }
}

T4 连续子段

一眼状压,两眼不会做

首先可以考虑对于最后组成连续 \(k\) 个数的 \(k\) 项,一定是先聚集在一个地方然后冒泡排序,所以这个交换次数可以拆成聚集在一起需要的次数和冒泡排序的次数(也就是逆序对个数)。

设状态 \(f_{i,S}\) 表示考虑到第 \(i\) 项,最终的 \(k\) 个数情况为 \(S\),则我们对于每个数有两种转移方式:

  1. \(i\) 作为最后的 \(k\) 个数出现,其贡献为 \(i\) 作为末尾的逆序对数目
  2. \(i\) 不作为最后的 \(k\) 个数出现,那么因为最后 \(k\) 个数要聚集在一起,所以要不就是 \(i\) 左边的最终项全到 \(i\) 右边,要么就是反过来,所以这个贡献为 \(\min(\operatorname{popcount}(S),k-\operatorname{popcount}(S))\)

然后发现倒序枚举 \(S\) 可以滚掉一位,时间复杂度为 \(O(2^kn)\)

点击查看代码
#include<bits/stdc++.h>
#define N 205
#define bitcnt __builtin_popcount
#define inf 0x3f3f3f3f
using namespace std;

int n,k,a[N],f[1<<16],ans=inf,range;
vector<int> vec[N];

int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++) scanf("%d",a+i),a[i]--;
    memset(f,0x3f,sizeof(f));
    f[0]=0;range=(1<<k)-1;
    for(int i=1;i<=n;i++){
        for(int j=range;j>=0;j--){
            int cnt=bitcnt(j);
            if(!(j&(1<<a[i]))) f[j|(1<<a[i])]=min(f[j|(1<<a[i])],f[j]+bitcnt(j&(~((1<<a[i])-1))));
            f[j]+=min(cnt,k-cnt);
        }
    }
    cout<<f[range];
}

标签:cnt,int,sum,lst,序列,CSP,模拟,define
From: https://www.cnblogs.com/Rolling-star/p/17577752.html

相关文章

  • strncmp/strstr 模拟实现
    constchar*my_strstr(constchar*str1,constchar*str2){ assert(str1&&str2); if(!*str2)//逆反逻辑,非0为真,假假为真 returnstr1; constchar*p1=NULL;//不改变str1和str2 constchar*p2=NULL; constchar*start=str1; while(*start) { p1=start;//p1需......
  • C语言模拟银行排队叫号系统(链队)
    一.队列队列是一种具有先进先出(FIFO)特性的线性数据结构,它只允许在队列的两端进行插入和删除操作。队列的一端称为队尾(rear),另一端称为队头(front)。新元素总是插入在队列的队尾,而从队列中删除元素时则总是删除队头元素。由于队列具有FIFO特性,因此队列通常用于需要按照顺序处理数据的场......
  • CSP模拟3 <反思>
    t3:不要随便用mapt4:代码转移要删全首先考虑暴力,类似线段树,首先你要先dfs出每个节点子树的左右节点,然后修改查询时要考虑左儿子右边界是否大于查询左边界,右儿子左边界是否小于查询有边界,进行\(dfs\)\((46pts)\)点击查看代码#include<bits/stdc++.h>#defineintlonglongu......
  • CSP 模拟 3
    今天感觉很热,但是天气转凉的时候我也该退役了吧。今日推歌:透明哀歌-n-buna/Gumiecho-Crusher-P/GumiEnglish歌词Theclockstoppedticking,时钟停止发出嘀嗒声Foreverago.在很久以前HowlonghaveIbeenup?我究竟醒来了多久?Idon'tknow.我不知道Ican't......
  • CSP 模拟 2
    感觉像是noi模拟赛多了个pT1F咋做都行,但是考场上的正确做法被后来优化RE了,痛失60pts其中一种做法是考虑只有\(a_1\oplusb_i\)有可能成为答案,然后验证即可T2S定义dp状态\(f_{i,j,k,0/1/2}\)为用了\(i\)个红球,\(j\)个绿球,\(k\)个红球,并且最后一位是什么球......
  • java 爬虫模拟登陆 拿到cookies
    实现Java爬虫模拟登录获取Cookies概述在这篇文章中,我将教你如何使用Java编程语言实现爬虫模拟登录并获取Cookies。爬虫模拟登录是一种常见的网络爬虫技术,它可以模拟用户登录网站,获取登录后才能访问的资源。流程概览下面是整个模拟登录获取Cookies的流程概览:步骤描述......
  • 模拟飞行开发任务进度
    第一周(截止2023.7.23上午)任务主要进度:跟着做的案例为Stack-O-Bot,有官方的文档以及游戏教学过程,比较适合新手进行学习,根据官方给的教学,大体上复现了他的效果。正在学习蓝图类模型,类似于图形化的编程界面?编程的重点是逻辑的设计,需要考虑好每一个过程的关系以及物理过程(这个在......
  • P7074 [CSP-J2020] 方格取数 题解
    题目:题目描述设有n*m 的方格图,每个方格中都有一个整数。现有一只小熊,想从图的左上角走到右下角,每一步只能向上、向下或向右走一格,并且不能重复经过已经走过的方格,也不能走出边界。小熊会取走所有经过的方格中的整数,求它能取到的整数之和的最大值。输入格式第一行有两个整......
  • Qt(5.8.0)-Cmd模拟(纯手写)
    以下是对上述Qt程序的详细博客,使用Markdown的代码块方式呈现:Qt编程:实现一个简单的命令行窗口Qt是一种跨平台的C++应用程序开发框架,可以用于开发各种类型的应用程序,包括图形界面(GUI)应用程序。本文将介绍如何使用Qt框架实现一个简单的命令行窗口,类似于Windows的运行框,用户可以在......
  • 「赛后总结」20230722 CSP 模拟赛
    「赛后总结」20230722CSP模拟赛点击查看目录目录「赛后总结」20230722CSP模拟赛反思题解T1回文思路代码T2快速排序思路代码T3混乱邪恶思路代码T4校门外歪脖树上的鸽子思路吓死我了我还以为K8He不更博了。为啥前天模拟赛不写啊?打过,没参加。为啥昨天模拟赛不......