今日习题
1栈(题目链接)
这个题是个思维题,可能一开始会想到找规律,但是发现这个序列可以从每俩个数字中间拆开成为这俩个序列的组合,就是个复杂一点的递推,看题解以后发现这就是卡特兰数,代码如下。
#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#define ll long long int
const int mod=1e9+7;
using namespace std;
string s,s1;
ll a[202000];
int main()
{
ios::sync_with_stdio(false);
ll n,k,i,j,m=0,sum=0,pi,ans=-0x3f3f3f3f;
cin>>n;
a[0]=1;
a[1]=1;
for(i=2;i<=n;i++)
{
for(j=0;j<i;j++)
{
a[i]+=a[j]*a[i-j-1];
}
}
cout<<a[n];
return 0;
}
2开心的金明(题目链接)
这个题是个简单的动态规划,类似于01背包问题,每个物品的价值可直接认为已知价值乘以重要度,具体见代码如下。
#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#define ll long long int
const int mod=1e9+7;
using namespace std;
struct node
{
int v,w;
}a[20010];
int b[30010];
int main()
{
ios::sync_with_stdio(false);
ll n,k,i,j,m=0,sum=0,pi,ans=-0x3f3f3f3f,id;
cin>>m>>n;
for(i=0;i<n;i++)
{
cin>>a[i].v>>a[i].w;
a[i].w*=a[i].v;
}
for(i=0;i<n;i++)
{
for(j=m;j>=0;j--)
{
if(j>a[i].v)
{
b[j]=max(b[j],b[j-a[i].v]+a[i].w);
}
}
}
cout<<b[m];
return 0;
}
3多项式输出(题目链接)
这个题乍一看特别水,我之所以感觉应该写一下的原因是我wa了好几发,这个题让我更加注意细节,以免在比赛场上出现这种问题搞自己心态,对于正负号以及负一和一的处理,代码如下(比较lj)。
#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
#define ll long long int
const int mod=1e9+7;
using namespace std;
int b[30010];
int main()
{
ios::sync_with_stdio(false);
ll n,k,i,j,m=0,sum=0,pi,ans=-0x3f3f3f3f,id;
cin>>n;
for(i=0;i<=n;i++)
{
cin>>b[i];
}
j=n-1;
if(abs(b[0])!=1)
cout<<b[0]<<"x"<<"^"<<n;
else
{
if(b[0]>0)
cout<<"x"<<"^"<<n;
else if(b[0]<0)
cout<<"-"<<"x"<<"^"<<n;
}
for(i=1;i<n-1;i++)
{
if(b[i]>0&&b[i]!=1)
{
cout<<"+"<<b[i]<<"x"<<"^"<<j;
}
else if(b[i]<0&&b[i]!=-1)
{
cout<<b[i]<<"x"<<"^"<<j;
}
else
{
if(b[i]==1)
{
cout<<"+"<<"x"<<"^"<<j;
}
else if(b[i]==-1)
{
cout<<"-"<<"x"<<"^"<<j;
}
}
j--;
}
if(b[n-1]>0&&b[n-1]!=1)
{
cout<<"+"<<b[n-1]<<"x";
}
else if(b[n-1]<0&&b[n-1]!=-1)
{
cout<<b[n-1]<<"x";
}
else
{
if(b[n-1]>0)
cout<<"+"<<"x";
else if(b[n-1]<0)
cout<<"-"<<"x";
}
if(b[n]>0)
{
cout<<"+"<<b[n];
}
else if(b[n]<0)
{
cout<<b[n];
}
/*else
{
if(b[n]==1)
cout<<"+"<<"x";
else if(b[n]==-1)
cout<<"-x";
}*/
return 0;
}
4石子合并(题目链接)
这个题是个经典的三维动态规划,不得不说,确实有时候数据范围也会提示你应该朝哪个时间复杂度的算法去想。本题的石子排列是一个环形,我们在数组中可以通过将已知石子排列增长为原来二倍,将原本的头和尾相接,将石子序列复制一遍,最后处理的时候从头遍历一遍原本的石子序列长度的区间即可。首先求前缀和,然后对于每个区间,可以被中间的任意一个位置分割为两个区间,假设这俩个区间的花费已知,则所求区间等于这俩个区间花费之和加上这个区间每个石头的花费,每个区间能被以此类推分为若干个,求其最大值(最小值)即可。具体代码如下。
#include<cmath>
#include <iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<cstring>
#include<math.h>
#include<stack>
#include<algorithm>
#include<queue>
#include<bitset>
using namespace std;
int dp[610][610],a[1010],sum[1010];
int main()
{
ios::sync_with_stdio(false);
int n,m,i,j,k;
memset(dp,0x3f,sizeof(dp));
memset(sum,0,sizeof(sum));
cin>>n;
for(i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=a[i]+sum[i-1];
dp[i][i]=0;
}
for(i=n+1;i<=2*n;i++)
sum[i]=a[i-n]+sum[i-1],dp[i][i]=0;
for(k=1;k<=2*n;k++)
for(i=k;i>0;i--)
{
for(j=i;j<k;j++)
{
if(i==k)
dp[i][k]=0;
else
dp[i][k]=min(dp[i][k],dp[j+1][k]+dp[i][j]+sum[k]-sum[i-1]);
}
}
int ans=0x3f3f3f3f;
for(i=1;i<=n;i++)
ans=min(dp[i][i+n-1],ans);
for(i=0;i<401;i++)
for(j=0;j<401;j++)
dp[i][j]=0;
for(k=1;k<=2*n;k++)
for(i=k;i>0;i--)
{
for(j=i;j<k;j++)
{
if(i==k)
dp[i][k]=0;
else
dp[i][k]=max(dp[i][k],dp[j+1][k]+dp[i][j]+sum[k]-sum[i-1]);
}
}
int aps=-1;
for(i=1;i<=n-1;i++)
aps=max(dp[i][i+n-1],aps);
cout<<ans<<endl<<aps;
return 0;
}