卷首语:
好长时间没敲题,太水了。。。。思维慢死了。。。。
Problem 1537 - A - Stones I
题目链接:
http://acm.whu.edu.cn/land/problem/detail?problem_id=1537
题目意思:
有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; }
题目链接:
http://acm.whu.edu.cn/land/problem/detail?problem_id=1538
题目意思:
有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
http://acm.whu.edu.cn/land/problem/detail?problem_id=1540
题目意思:
求斐波拉契数列的前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; }