第三屆華中區全國程式設計大賽暨武大校賽網賽
阿新 • • 發佈:2019-01-26
卷首語:
好長時間沒敲題,太水了。。。。思維慢死了。。。。
Problem 1537 - A - Stones I
題目連結:
題目意思:
有n堆石頭,第i堆有ai和bi屬性,每次拿一堆(假設第i堆)後,所有的石頭的a值都減去bi.求最後拿到的a的和的最大值。
解題思路:
列舉。
題目本質意思就是求拿了m堆後 sigma(a)-m*sigma(b)的最大值。列舉m,按ai-m*bi排序,求出前面的m個和,再比較求出最大值。
程式碼:
Problem 1538 - B - Stones II#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; }
題目連結:
題目意思:
有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;
}