1. 程式人生 > >第三屆華中區全國程式設計大賽暨武大校賽網賽

第三屆華中區全國程式設計大賽暨武大校賽網賽

卷首語:

好長時間沒敲題,太水了。。。。思維慢死了。。。。

Problem 1537 - A - Stones I

題目連結:

題目意思:

有n堆石頭,第i堆有ai和bi屬性,每次拿一堆(假設第i堆)後,所有的石頭的a值都減去bi.求最後拿到的a的和的最大值。

解題思路:

列舉。

題目本質意思就是求拿了m堆後 sigma(a)-m*sigma(b)的最大值。列舉m,按ai-m*bi排序,求出前面的m個和,再比較求出最大值。

程式碼:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;

#define Maxn 1100

struct Node
{
    ll a,b,v;
}t1[Maxn];
ll n,ans;

bool cmp(struct Node a,struct Node b)
{
    return a.v>b.v;
}

ll MM(ll a,ll b)
{
    return a>b?a:b;
}

int main()
{
    while(scanf("%lld",&n)&&n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld",&t1[i].a,&t1[i].b);
            t1[i].v=t1[i].a-t1[i].b;
        }
        sort(t1+1,t1+n+1,cmp);
        ans=t1[1].v;

        for(int i=2;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                t1[j].v=t1[j].a-i*t1[j].b;
            }
            sort(t1+1,t1+n+1,cmp);

            ll temp=0;
            for(int j=1;j<=i;j++)
                temp+=t1[j].v;
            ans=MM(ans,temp);
          // printf("i:%d %lld\n",i,ans);
        }
        printf("%lld\n",ans);



    }
    return 0;
}
Problem 1538 - B - Stones II

題目連結:

題目意思:

有n堆石頭,每拿一堆(假設是第i堆),沒有被拿的石頭堆的a都要減去bi,求能夠拿的a的和的最大值。

解題思路:

動態規劃+貪心

挖掘題目意思,可知當要選剩餘堆的個數j確定下來後,當前堆對後面的影響是a[i]-b[i]*j.後面有多少個堆就要減多少次。

分析知當堆確定後,a值不會對結果產生影響,只有b值會產生影響,顯然b小的放到前面結果更優。所以先按b值從小到大排序。

dp[i][j]:表示第i堆後還要選j堆能達到的最大值。

轉移方程:

dp[i][j]=max(dp[i-1][j],dp[i-1][j+1]+a[i]-b[i]*j) ; //要麼選要麼不選

程式碼:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 1100

struct Inf
{
    int a,b;
}save[Maxn];
LL dp[Maxn][Maxn];
int n;


LL Max(LL a,LL b)
{
    return a>b?a:b;
}

bool cmp(struct Inf a,struct Inf b)
{
    return a.b<b.b;
}

int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);

   while(scanf("%d",&n)&&n)
   {
       for(int i=1;i<=n;i++)
           scanf("%lld%lld",&save[i].a,&save[i].b);
       memset(dp,-INF,sizeof(dp)); //無效狀態
       //printf("%d\n",dp[1][1]);
       sort(save+1,save+n+1,cmp);  //順序 肯定對b從小到大比較優
       for(int i=0;i<=n;i++)
            dp[0][i]=0;

       for(int i=1;i<=n;i++)
       {
           for(int j=0;j<=n;j++)
               dp[i][j]=Max(dp[i-1][j],dp[i-1][j+1]+save[i].a-save[i].b*j);

       }
       printf("%lld\n",dp[n][0]);

   }
   return 0;
}


Problem 1540 - D - Fibonacci

題目連結:

題目意思:

求斐波拉契數列的前n項的立方和(n<=10^9) 第一項和第二項是1、1

解題思路:

矩陣快速冪

構造矩陣

F(n)^3=(F(n-1)+F(n-2))^3=F(n-1)^3+F(n-2)^3+3*F(n-1)^2*F(n-2)+3*F(n-1)*F(n-2)^2


程式碼:

//#include<CSpreadSheet.h>

#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define Maxn 8
LL n;

struct Mar
{
    int row,col;
    LL s[Maxn][Maxn];

    void init(int a,int b)
    {
        row=a;
        col=b;
        memset(s,0,sizeof(s));
    }

};

Mar operator * (const Mar &a,const Mar &b)
{
   Mar c;
   c.init(a.row,b.col);

   for(int k=1;k<=a.col;k++)
        for(int i=1;i<=a.row;i++)
       {
           if(!a.s[i][k])
                continue;
           for(int j=1;j<=b.col;j++)
           {
               if(!b.s[k][j])
                    continue;
               c.s[i][j]=(c.s[i][j]+(a.s[i][k]*b.s[k][j])%M+M)%M;
           }
       }
    return c;
}

Mar ans,ba;

void init()
{
    ans.init(5,1);
    ans.s[1][1]=2,ans.s[2][1]=1,ans.s[3][1]=1,ans.s[4][1]=3,ans.s[5][1]=3;

    ba.init(5,5);

    for(int i=1;i<=5;i++)
        ba.s[1][i]=1;
    for(int i=2;i<=5;i++)
        ba.s[2][i]=1;
    ba.s[3][2]=1;
    ba.s[4][2]=3;
    ba.s[4][5]=1;
    ba.s[5][2]=3;
    ba.s[5][4]=1;
    ba.s[5][5]=2;

}
int main()
{
   //freopen("in.txt","r",stdin);
   //freopen("out.txt","w",stdout);

   while(scanf("%lld",&n)&&n)
   {
       if(n==1)
       {
           printf("1\n");
           continue;
       }
       if(n==2)
       {
           printf("2\n");
           continue;
       }
       n-=2;

       init();
       while(n)
       {
           if(n&1)
               ans=ba*ans;
           n>>=1;
           ba=ba*ba;
       }
       printf("%lld\n",ans.s[1][1]);




   }
   return 0;
}