9.6 字节跳动笔试
t1
大概题意
有个楼梯比较高,问有多少种可以方式可以走上去,但有特殊得要求:一是每次可以走一步或者两步,二是不能连续的走两步
计算有多少种方法到达顶层
输入:楼层的层数
输出:一共有多少种走法
思路:直接dp就好了,设dp方程为dp[i][2],dp[i][0]表示走一步之后达到第i层,那么转移方程就是dp[i][0]+=dp[i-1][0]+dp[i-1][1]
dp[i][1]表示走两步之后达到第i层,那么转移方程就是dp[i][1]+=dp[i-2][0];
答案就是到达第n层的两种状态dp[n][0]+dp[n][1]
#include<map>
#include<queue>
#include<time.h>
#include<limits.h>
#include<cmath>
#include<ostream>
#include<iterator>
#include<set>
#include<stack>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep_1(i,m,n) for(int i=m;i<=n;i++)
#define mem(st) memset(st,0,sizeof st)
inline int read()
{
int num=0, w=0;
char ch=0;
while (!isdigit(ch))
{
w|=ch=='-';
ch = getchar();
}
while (isdigit(ch))
{
num = (num<<3) + (num<<1) + (ch^48);
ch = getchar();
}
return w? -num: num;
}
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef pair<double,double> pdd;
const int inf = 0x3f3f3f3f;
const int N=2e6+10;
#define int long long
int dp[110][2];
void solve()
{
int n;
cin>>n;
dp[1][0]=1;
dp[1][1]=0;
dp[2][1]=1;
dp[2][0]=1;
for(int i=3;i<=n;i++)
{
dp[i][0]+=dp[i-1][0]+dp[i-1][1];
dp[i][1]+=dp[i-2][0];
}
cout<<dp[n][0]+dp[n][1]<<endl;
}
signed main()
{
int t=1;
while(t--)
solve();
return 0;
}
t3
题目大意
给定一个长度为n的整数序列S,然后把序列复制成m份,也就是变成了n*m的序列,然后在这个新的序列中选取一段连续的整数,使得和最大。
和最大是多少?注意:序列中有负数或者0,至少选一个数,不能不选
思路:首先如果m等于1时,此时此时就是在长度为n的数组里面选最大的连续字段和,我们可以用dp来做
当m等于2的时候,也就是直接把数组复制一遍接到后面,然后dp,n的范围很小,dp完全足够
然后当m>2的时候,就是我们找到最大子串之后,还要枚举我们的答案里面要有几个这样的最大字串,当有两个的时候,也就是可以看作一个最大字串+一个整串,然后枚举个数就好
需要注意的时,此题至少选一个,那么我们可以把ans设置为0,如果最大字串比0小的话,说明都是负数,我们就可以直接输出一个最大的负数就好了
具体看代码
#include<map>
#include<queue>
#include<time.h>
#include<limits.h>
#include<cmath>
#include<ostream>
#include<iterator>
#include<set>
#include<stack>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep_1(i,m,n) for(int i=m;i<=n;i++)
#define mem(st) memset(st,0,sizeof st)
inline int read()
{
int num=0, w=0;
char ch=0;
while (!isdigit(ch))
{
w|=ch=='-';
ch = getchar();
}
while (isdigit(ch))
{
num = (num<<3) + (num<<1) + (ch^48);
ch = getchar();
}
return w? -num: num;
}
typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef pair<double,double> pdd;
const int inf = 0x3f3f3f3f;
const int N = 1e6 + 10;
#define int long long
int a[N] , dp[N];
void solve()
{
int n , m , sum = 0 , ma = 0 , ans = 0;
cin >> n >> m ;
//直接赋值,拼成两段
for(int i=1; i<=n; i++)
cin >> a[i] , a[i + n] = a[i] , sum += a[i];
//先求一边最大子序列的和
for(int i=1; i<=2*n; i++)
dp[i] = max(max(dp[i - 1] + a[i] , 0ll) , a[i]);
for(int i=1; i<=n; i++)
ans = max(ans , dp[i]);
//如果只是一次
if(m == 1)
{
//ans是0,说明都比0小 ,说明都是负数
if(!ans)
{
//找到最大的那个负数
ans = -0x3f3f3f3f3f3f3fll;
for(int i=1; i<=n; i++)
ans = max(ans , a[i]);
}
cout << ans << '\n' ;
return ;
}
//如果m不是1,那么,就找最大的子段
for(int i=1; i<=2*n; i++)
ma = max(ma , dp[i]);
//枚举中间有几个连续的整段
for(int i=2; i<=m; i++)
ans = max(ans , sum * (i - 2) + ma);
//如果是0的话,说明都是负数
if(!ans)
{
//就直接找一个最大的负数输出
ans = -0x3f3f3f3f3f3f3fll;
for(int i=1; i<=n; i++)
ans = max(ans , a[i]);
}
cout << ans << '\n';
}
signed main()
{
int t=1;
while(t--)
solve();
return 0;
}