• NOIP1999提高组 题解报告


    T1 导弹拦截

    题目大意:依次有(n)(n le 10^5))枚导弹,一套导弹拦截系统只能拦截一系列高度递减的导弹(一套系统拦截的弹道不一定相邻)。求一套系统最多能拦截多少导弹,以及最少需要几套系统。

    很显然,一套系统最多拦截导弹数即为导弹高度的最长不上升子序列,而需要系统数即为最长下降子序列。

    直接(O(nlogn))解决即可。

    (Code:)

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int N=1e5+5;
    int n,a[N],b[N],k1,k2,c[N];
    int main()
    {
        while(~scanf("%d",&a[++n]));--n;
        b[++k1]=a[1],c[++k2]=a[1];
        for(int i=2;i<=n;++i)
        {
            if(a[i]<=b[k1]) b[++k1]=a[i];
            else
            {
                int pos=upper_bound(b+1,b+k1+1,a[i],greater<int>())-b;
                b[pos]=a[i];
            }
            if(a[i]>c[k2]) c[++k2]=a[i];
            else
            {
                int pos=lower_bound(c+1,c+k2+1,a[i])-c;
                c[pos]=a[i];
            }
        }
        printf("%d
    %d",k1,k2);
        return 0;
    }
    
    

    T2 回文数

    题目大意:给你一个(n)进制数(m),可进行在(n)进制下的如下操作:(m)加上自身的倒序数(如(56)(65))。如此反复操作,求多少次操作后可得到一个回文数。

    简单的模拟,要注意特判(n > 10)的时候。

    (Code:)

    #include<iostream>
    #include<cstring>
    #include<string>
    using namespace std;
    int x,n,sum,a[1001];
    string s;
    inline bool hw(int n)
    {
    	for(int i=1;i<=n/2;i++)
    		if(a[i]!=a[n-i+1]) return false;
    	return true;
    }
    inline int jia(int n)
    {
    	int c[1001]={0};
    	for(int i=1;i<=n;i++)
    	{
    		c[i]+=a[i]+a[n-i+1];
    		c[i+1]+=c[i]/x;
    		c[i]%=x;
    	}
    	if(c[n+1]) n++;
    	for(int i=n;i>=1;i--) a[i]=c[i];
    	return n;
    }
    int main()
    {
    	cin>>x>>s;n=s.size();
    	for(int i=1;i<=n;++i)
    	{
    		if(s[i-1]<65) a[i]=s[i-1]-'0';
    		else a[i]=s[i-1]-55;//特判字母
    	}
    	while(sum<=30)
    	{
    		if(hw(n))
    		{
    			printf("STEP=%d",sum);
    			return 0;
    		}
    		++sum,n=jia(n);
    	}
    	puts("Impossible!");
    }
    
    

    T3 旅行家的预算

    题目大意:在长为(D_1)一条路上,有(n)个加油站,每个加油站有一个油价(p_i)和离起点的距离(d_i)。现在给出油箱容量(C)和每升汽油能行驶的距离(D_2),求是否能到终点;如果能,输出最小花费。

    仍然是模拟,还加了点贪心。

    • 在一个加油站所需要加的油,就是能够支持它到达下一个油价比它低的加油站的量

    • 如果在这个加油站即使加满油,都不能到达一个比它油价低的加油站,就把油箱加满,前往能够到达的加油站中油价最低的那个(贪心地想,这种决策肯定是能省钱的)

    (Code:)

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define db double
    int n;
    db D1,v,D2,P[233],D[233];
    db solve()
    {
        db s=v*D2;//车能开的距离
        db sum=(1.0*D[1]/D2)*P[0];//总费用
        db sumD=D[1];
        if(D[1]>s) return -1;
        db now=P[0];//设为当前使用的油价
        for(int i=1;i<=n;++i)
            if(P[i]-P[i-1]>s) return -1;
        int i=1;
        while(i<=n)
        {
            if(P[i]>=now)
            {
                sumD+=D[i+1]-D[i];
                if(sumD>s)
                {
                    sum+=(1.0*(s-(sumD-(D[i+1]-D[i])))/D2)*now;
                    now=P[i],sumD=sumD-s;
                    sum+=(1.0*sumD/D2)*now;
                }
                else sum+=(1.0*(D[i+1]-D[i])/D2)*now;
                ++i;
            }
            else now=P[i],sumD=0;
        }
        return sum;
    }
    int main()
    {
        scanf("%lf%lf%lf%lf%d",&D1,&v,&D2,&P[0],&n);
        for(int i=1;i<=n;i++)
            scanf("%lf%lf",&D[i],&P[i]);
        D[n+1]=D1;
        db sum=solve();
        if(sum<0) puts("No Solution");
        else printf("%.2lf
    ",sum);
        return 0;
    }
    
    

    T4 邮票面值设计

    题目大意:给定一个信封,最多只允许粘贴(n)张邮票,有(k)((n + k le 15))种邮票要用(所有的邮票数量都足够),如何设计邮票的面值,能得到最大值(MAX),使在(1)(MAX)之间的每一个邮资值都能得到。

    很显然是个爆搜题,不过爆搜的范围怎么确定呢?
    我们发现,如果令$p = (选完上一个数可拼成的面值,则当前数的范围为)[上一个数 + 1 , p + 1]((这个道理仔细想一下就明白了) 确定最大面值的问题,就可以用完全背包来解决啦! 定义)dp[i](为拼成)i(最少需要的邮票数,则状态转移方程为:)dp[i] = min(dp[i],dp[i - a[j]] + 1)( )Code:$

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int inf=0x3f3f3f3f;
    #define rg register
    vector<int>ans,temp;
    int n,k,dp[2333],Ans;
    inline int f()
    {
        memset(dp,inf,sizeof dp),dp[0]=0;
        for(rg int i=1;;++i)
        {
            for(rg int j=0;j<(int)temp.size() && temp[j]<=i;++j)
                dp[i]=min(dp[i],dp[i-temp[j]]+1);
            if(dp[i]>n)
            {
                if(i>Ans+1) Ans=i-1,ans=temp;
                return i-1;
            }
        }
    }
    inline void dfs(int d)
    {
        int p=f();
        for(rg int i=temp[(int)temp.size()-1]+1;i<=p+1;++i)
        {
            temp.push_back(i),f();
            if(d<k) dfs(d+1);
            temp.pop_back();
        }
    }
    int main()
    {
        scanf("%d%d",&n,&k);temp.push_back(1);
        dfs(2);
        for(rg int i=0;i<ans.size();++i) printf("%d ",ans[i]);
        printf("
    MAX=%d",Ans);
        return 0;
    }
    
    
  • 相关阅读:
    Python3爬取前程无忧数据分析工作并存储到MySQL
    MySQL操作数据库和表的基本语句(DDL
    MyBatis的增删改查操作
    指定方向或者位置移动
    AI-Tank
    转载人家写的CURSOR
    Ajax学习整理笔记
    全面解析注解
    java调用存储过程mysql
    JAVA如何调用mysql写的存储过程
  • 原文地址:https://www.cnblogs.com/p-z-y/p/11720355.html
Copyright © 2020-2023  润新知