p1802,p1806,p1808

  新高一第二期培訓開始了,雖然不是我的班也來快樂了.早上來的時候見到了新高一去軍訓的場面,還挺感動的.

  然後上午並沒人問我,我就在校oj刷題,一上午整了三道,美滋滋.

  

 

 

   p1802一看就是一個動態規劃.考慮每個樹能取的狀態和前一個樹相關,而且不止與前一個樹高度相關,還和前前一個樹相關.所以我設了四個狀態表示當前樹的高度和與前一個樹的關係.分別是:最低,中等且前一個樹更高,中等且前一個樹更低,最高.

 

 

   這樣就可以開始轉移了,但是如果給f[1]的四個狀態都賦值就會使得最後的答案不明確,因爲成環的原因嘛.那麼可以考慮關於一樹的狀態再分狀態.f[i][j][k]表示1樹狀態爲j,樹i狀態爲k時的最大觀賞值.轉移也很好轉移,答案是f[n][1..4][1..4]中的最大值.但是我懶省事就複製粘貼了四個.

long long a[100010][5],f[100010][5];
long long maxx(long long a,long long b,long long c)
{
    a=a>b?a:b;
    return a>c?a:c;
}
int main()
{
    int n=read();
    for(int i=1;i<=n;i++)
    {
        a[i][1]=read();
        a[i][2]=read();
        a[i][3]=read();
    }    
    //1:
    f[1][1]=a[1][1];
    f[1][2]=f[1][3]=f[1][4]=-10000000;
    for(int i=2;i<=n;i++)
    {
        f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]);
        f[i][2]=a[i][2]+f[i-1][4];
        f[i][3]=a[i][2]+f[i-1][1];
        f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]);
    }
    long long ans;
    ans=max(f[n][3],f[n][4]);
    //2
    f[1][2]=a[1][2];
    f[1][1]=f[1][3]=f[1][4]=-10000000;
    
    for(int i=2;i<=n;i++)
    {
        f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]);
        f[i][2]=a[i][2]+f[i-1][4];
        f[i][3]=a[i][2]+f[i-1][1];
        f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]);
    }
    ans=max(ans,f[n][4]);
    //3
    f[1][3]=a[1][2];
    f[1][1]=f[1][2]=f[1][4]=-10000000;
    for(int i=2;i<=n;i++)
    {
        f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]);
        f[i][2]=a[i][2]+f[i-1][4];
        f[i][3]=a[i][2]+f[i-1][1];
        f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]);
    }
    ans=max(ans,f[n][1]);
    //4
    f[1][4]=a[1][3];
    f[1][1]=f[1][2]=f[1][3]=-10000000;    
    for(int i=2;i<=n;i++)
    {
        f[i][1]=a[i][1]+max(f[i-1][4],f[i-1][3]);
        f[i][2]=a[i][2]+f[i-1][4];
        f[i][3]=a[i][2]+f[i-1][1];
        f[i][4]=a[i][3]+max(f[i-1][1],f[i-1][2]);
    }
    ans=maxx(ans,f[n][1],f[n][2]);
    cout<<ans;
    return 0;
}
p1802

  p1806讀懂了題意後考慮不寫程序的話普通人會怎麼做.應該先看最後一位能不能++,如果能就++走人,否則看倒數第二位能不能++,並且使得倒數第一位爲倒數第二位原來的字母+2.如果能就這樣做,以此類推.

  那麼對於第i位只需判斷是否w-i<t-ans[i].如果可以就枚舉後面所有位,使得ans[j]=ans[j-1]+1;.

char s,t;
int w;
char ans[30];
void work()
{
    for(int i=w;i;i--)
        if(ans[i]<t&&w-i<t-ans[i])
        {
            ans[i]=ans[i]+1;    
            for(int j=i+1;j<=w;j++)
                ans[j]=ans[j-1]+1;
            return ;
        }
    exit(0);
}
int main()
{
    s=read()+'a'-1;t=read()+'a'-1;w=read();
    for(int i=1;i<=w;i++)
        cin>>ans[i];
    for(int i=1;i<=5;i++)
    {
        work();
        for(int j=1;j<=w;j++)
            cout<<ans[j];
        cout<<endl;
    }
    return 0; 
}
p1804

  p1808答案就是c(m+n,m)的後一百位.我會高精度!但是除法不太行,因爲求不了逆元.

  考慮在班裏求組合數,先把分子分母寫出來,然後上下消去公因數,然後再把分子乘起來的操作.類比一下,先求出1到m+n的質數並且存起來,對於需要求的組合數,只需要記錄m+1到m+n和2到n的數的質因數還剩下多少,再用高精度乘起來.高精度乘單精度還是很好寫的.

  這道是我上午寫的最簡單的題了.

long long num[100000],sum[100010],k;
long long ans[30];
bool zhi(int x)
{
    for(int i=sqrt(x*1.0);i>=2;i--)
        if(x%i==0)
            return 0;
    return 1;
}
void Add(long long  x)
{
    for(int i=1;x>=num[i]&&i<=k;i++)
    {
        while(x%num[i]==0)
            x=x/num[i],sum[i]++;
    }
    return ;
}
void Minus(long long x)
{
    for(int i=1;x>=num[i]&&i<=k;i++)
    {
        while(x%num[i]==0)
            x=x/num[i],sum[i]--;
    }
    return ;
}
void mul(long long x)
{
    for(int i=1;i<=20;i++)
        ans[i]=ans[i]*x;
    for(int i=1;i<=20;i++)
        ans[i+1]+=ans[i]/100000,ans[i]=ans[i]%100000;
    return ;
}
int main()
{
    int m=read(),n=read();
    if(m<n)
        swap(m,n);
    for(int i=2;i<=m+n;i++)
        if(zhi(i))
            k++,num[k]=i;
    for(int i=m+n;i>m;i--)
        Add(i);
    for(int i=2;i<=n;i++)
        Minus(i); 
    ans[1]=1;
    for(int i=1;i<=k;i++)
        while(sum[i])
            mul(num[i]),sum[i]--;
    for(int i=20;i;i--)
    {
        long long t=10000;
        while(t&&ans[i]/t==0)
            cout<<0,t=t/10;
        if(ans[i])
            cout<<ans[i];
        if(i%2)
            cout<<endl;
    }
    return 0;
}
p1806

 

  然後中午學弟問了我一道統計數字:

某次科研調查時得到了n(n<=200000)個自然數,每個數均不超過1500000000(1.5*10^9)。已知不相同的數不超過10000個,現在需要統計這些自然數各自出現的次數,並按照自然數從小到大的順序輸出統計結果。

  他們還沒學sort,桶排序也不行,這可咋辦呢?

  我一拍大腿,我會map!

  作爲map的忠實粉絲,即使map常數很大,但因爲它的簡單易行(與數組相似),我一直很喜歡用它艹一些題.

  map<long long,int>sum;來統計每個數的數量.然後用一個迭代器便利map裏的元素輸出即可.

map<long long,int> a;
long long n,x,maxx;
int main()
{
    n=read();
    while(n)
        a[read()]++,n--;
    map<long long,int>::reverse_iterator   iter;
    for(iter = a.rend(),iter--; iter != a.rbegin(); iter--)
    {
        write(iter->first);
        putchar(32);
        write(iter->second);
        putchar(10);
    } 
    write(iter->first);
    putchar(32);
    write(iter->second);     
    return 0;
} 
#92統計數字

  最後用map艹翻了一衆sort,.

 

   

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章