NOIP1999提升組 題解報告

T1 導彈攔截

題目大意:依次有\(n\)\(n \le 10^5\))枚導彈,一套導彈攔截系統只能攔截一系列高度遞減的導彈(一套系統攔截的彈道不必定相鄰)。求一套系統最多能攔截多少導彈,以及最少須要幾套系統。

很顯然,一套系統最多攔截導彈數即爲導彈高度的最長不上升子序列,而須要系統數即爲最長降低子序列。ios

直接\(O(nlogn)\)解決便可。spa

\(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\n%d",k1,k2);
    return 0;
}

T2 迴文數

題目大意:給你一個\(n\)進制數\(m\),可進行在\(n\)進制下的以下操做:\(m\)加上自身的倒序數(如\(56\)\(65\))。如此反覆操做,求多少次操做後可獲得一個迴文數。

簡單的模擬,要注意特判\(n > 10\)的時候。code

\(Code:\)ci

#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\),求是否能到終點;若是能,輸出最小花費。

仍然是模擬,還加了點貪心。get

  • 在一個加油站所須要加的油,就是可以支持它到達下一個油價比它低的加油站的量string

  • 若是在這個加油站即便加滿油,都不能到達一個比它油價低的加油站,就把油箱加滿,前往可以到達的加油站中油價最低的那個(貪心地想,這種決策確定是能省錢的)it

\(Code:\)io

#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\n",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:\)class

#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("\nMAX=%d",Ans);
    return 0;
}
相關文章
相關標籤/搜索