• [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
    ",ans+1);
    }
    void work()
    {
    	ans=1;
    	n=read();m=read();
    	if(m==1)
    		printf("%d
    ",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
    ",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('
    ');
        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('
    ');
        return 0;
    }
    
  • 相关阅读:
    django之--模型层(ORM语法)
    mysql问题记录
    CentOS系统内存使用问题(内存是拿来用的,而不是拿来看的)
    CentOS6&CentOS7安装FFmpeg
    django之--模板层
    Django之--视图层
    Django之ORM学习2--路由层
    Django之ORM学习
    Django入门
    第二版mq 数据结构选型
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11624745.html
Copyright © 2020-2023  润新知