[CSP-S模拟测试60]题解

回去要补一下命运石之门了……

A.嘟嘟噜

给定报数次数的约瑟夫,递推式为$ans=(ans+m)\% i$。

考虑优化,中间很多次$+m$后是不用取模的,这种情况就可以把加法变乘法了。问题在于如何找到下一次需要取模的位置。

解不等式$ans+km \ge i+k$即可,需要处理一下边界。

据说可以证明复杂度是$O(m \log n)$的,但我不是很会。

//考场代码 稍丑
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
	while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
	return x*f;
}
int n,m,T,ans=1;
void qj()
{
	for(int i=1;i<=n;i++)
		ans=(ans+m)%i;
	printf("%d\n",ans+1);
}
void work()
{
	ans=1;
	n=read();m=read();
	if(m==1)
		printf("%d\n",n);
	else if(n<=m)qj();
	else
	{
		ans=1;
		for(int i=1;i<=n;i++)
		{
			if(ans+m<i)
			{
				ans+=m;
				int times=(i-ans)/(m-1);
				if(i+times>n)
					times=n-i;
				ans+=times*m;i+=times;
				ans%=i;
			}
			else ans=(ans+m)%i;
		}
		printf("%d\n",ans+1);
	}
	return ;
}
int main()
{
	T=read();
	while(T--)work();
	return 0;
}

B.天才绅士少女助手克里斯蒂娜

C.凤凰院凶真

经典的LCIS问题。设$dp[i][j]$为a串考虑到$i$,b串考虑到$j$且以$j$为结尾的LCIS长度。

限定一下条件,$O(n^3)$暴力dp就很好写了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
    return x*f;
}
const int N=5005;
#define pa pair<int,int>
int n,m,a[N],b[N],dp[N][N],pre[N][N];
stack<int> s;
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    m=read();
    for(int i=1;i<=m;i++)
        b[i]=read();
    int ans1=-1,pos=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(a[i]==b[j])
            {
                for(int k=0;k<j;k++)
                    if(b[k]<b[j])
                        if(dp[i][j]<dp[i-1][k]+1)
                            dp[i][j]=dp[i-1][k]+1,pre[i][j]=k;
            }
        }
    for(int i=0;i<=m;i++)
        if(ans1<dp[n][i])ans1=dp[n][i],pos=i;
    int tim=n;
    s.push(pos);
    cout<<ans1<<endl;
    while(tim&&pos)
    {
        if(pre[tim][pos])
        {
            pos=pre[tim][pos];
            s.push(pos);
        }
        else tim--;
    }
    while(!s.empty())printf("%d ",b[s.top()]),s.pop();
    putchar(‘\n‘);
    return 0;
}

考虑优化。我们注意到,每次转移的条件是$a[i]=b[j] \ and\ b[j]<b[k]$,即$a[i]=b[j] \ and\ a[i]<b[k]$。j每次增加1,这个可选集合最多也只会增加1。所以可以直接去掉枚举k的循环,维护当前可选集合的最优解即可。

还有一个细节,记录前驱时要把两维的信息都记录,如果只记第二维的话各层状态会混用。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<stack>
using namespace std;
int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
    return x*f;
}
const int N=5005;
#define pa pair<int,int>
int n,m,a[N],b[N],dp[N][N],pre[N][N];
stack<int> s;
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    m=read();
    for(int i=1;i<=m;i++)
        b[i]=read();
    int ans1=-1,pos=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(a[i]==b[j])
            {
                for(int k=0;k<j;k++)
                    if(b[k]<b[j])
                        if(dp[i][j]<dp[i-1][k]+1)
                            dp[i][j]=dp[i-1][k]+1,pre[i][j]=k;
            }
        }
    for(int i=0;i<=m;i++)
        if(ans1<dp[n][i])ans1=dp[n][i],pos=i;
    int tim=n;
    s.push(pos);
    cout<<ans1<<endl;
    while(tim&&pos)
    {
        if(pre[tim][pos])
        {
            pos=pre[tim][pos];
            s.push(pos);
        }
        else tim--;
    }
    while(!s.empty())printf("%d ",b[s.top()]),s.pop();
    putchar(‘\n‘);
    return 0;
}

原文地址:https://www.cnblogs.com/Rorschach-XR/p/11624745.html

时间: 2024-10-09 06:23:43

[CSP-S模拟测试60]题解的相关文章

csp-s模拟测试60

csp-s模拟测试60       2019-10-05 RT. 又颓又垃圾. 状态低迷,题都交不上去. 交了也是爆零,垃圾玩家没有什么可说的,就是垃圾. A. 嘟嘟噜 $mlogn$的毒瘤做法. 贴一个不一样的毒瘤做法. 1 //ans=(ans+m)%i 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 #define re re

csps-s模拟测试60嘟嘟噜,天才绅士少女助手克里斯蒂娜,凤凰院凶真题解

题面:https://www.cnblogs.com/Juve/articles/11625190.html 嘟嘟噜: 约瑟夫问题 第一种递归的容易re,但复杂度较有保证 第二种适用与n大于m的情况 第三种O(n)用于n不太大或m大于n时 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define int lon

[CSP-S模拟测试59]题解

以后题解还是单独放吧. A.Divisors 根号筛求所有数的因子,扫一遍去重统计即可. #include<cstdio> #include<iostream> #include<cstring> #include<vector> #include<map> using namespace std; const int N=205; int a[N],m,n; map<int,int> bu; vector<int> re

CSP-S 模拟测试57题解

人生第一次A,B层一块考rank2,虽然说分差没几分,但还是值得纪念. 题解: T1 天空龙: 大神题,因为我从不写快读也没有写考场注释的习惯,所以不会做,全hzoi就kx会做,kx真大神级人物. T2 巨神兵: 大神题,一看数据范围这么小,我们考虑状压,最傻逼的暴力思路是压边,但是这显然不行.正解是压点,设$f[s]$为当前选定点集状态为$s$的方案数. 我们考虑转移,当前选定的点集肯定是可以通过边和没有连过来的点相连构成新的方案.所以转移所以我们考虑枚举补集的子集$k$,设$cnt$为s与k

CSP-S模拟测试69 题解

一如既往的垃圾,又回到了那个场场垫底的自己,明明考场上都想到正解了,但是就是拿不到分,可能是互奶把rp用光了吧以后一定加强训练代码能力. T1: 考场上一直yy矩阵快速幂,虽然自己矩阵快速幂一点都不会还是硬着头皮yy,发现不可做之后并没有及时转化思路,但其实自己预处理的数组就是正解. 切记:不仅矩阵快速幂是log的,普通快速幂也是2333 然后这题其实很水啊,我们设$dp[i][j]$为前$i$列放$j$个棋子的方案数,然后枚举最后一列放多少个棋子就好了. 转移方程为$dp[i][j]=\sum

[CSP-S模拟测试96]题解

以后不能再借没改完题的理由不写题解了…… A.求和 求$\sum \sum i+j-1$ 柿子就不化了吧……这年头pj都不考这么弱智的公式化简了…… 坑点1:模数不定,可能没有2的逆元,那么只要先把乘数里的2去掉就好了. 坑点2:1e18炸long long $\rightarrow$ 慢速乘即可 #include<cstdio> #include<iostream> #include<cstring> #include<vector> using name

[CSP-S模拟测试97]题解

A.小盆友的游戏 感觉题解解释的很牵强啊……还是打表找规律比较靠谱 对于每个人,它构造了一个期望函数$f(x)$,设它的跟班个数为$cnt[x]$,那么令$f(x)=2^{cnt[x]}-1$(??鬼知道为什么要等于这个) 然后再定义当前局面的期望函数为每个人期望函数之和. 然后你会发现每次猜拳后局面期望函数变化量都是1 那么期望步数其实就是终止局面期望函数值-初始局面期望函数值 $ans=2^{n-1}-1-\sum (2^{cnt[x]}-1)$ #include<bits/stdc++.h

[CSP-S模拟测试53]题解

A.u 只涉及到区间修改可以考虑差分,然而如果每一行都差分复杂度还是过高.我们发现差分标记也是连续的(一行横着的一行斜着的),所以可以维护两个 差分的差分,扫两遍统计即可. #include<cstdio> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=2005; int read() { int x=0,f=1;char ch=ge

模拟测试60

T1: 约瑟夫问题. 经证(da)明(biao)可知,最终答案计算方法是: 答案由$1$开始,每次加$m$,若大于次数加一,就对次数加一取模. 可以$O(1)$计算每次取模的位置,取模不超过$mlogn$次,于是时间复杂度为$O(mlogn)$. T2: 普及:向量叉积:$v_1=(x_1,y_1),v_2=(x_2,y_2) \Rightarrow \vec{v_1}\times \vec{v_2}=x_1*y_2-x_2*y_1$ 然而我只会拆平方干推式子: $\large \begin{a