题解报告
基本的一些理解和问题都在注释中
A:Insert Digit
找到第一个小于输入数字的数的位置塞进去就好了,可以细推,但是粗略想想也能知道
#include <bits/stdc++.h>
using namespace std;
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--)
{
string s;
int len,num;
cin>>len>>num>>s;
int flag=1;
for(int i=0;i<len;i++)//遇到第一个小的就输出,等于的不行。一定等于的话不一定是最优秀的,
{
if(flag&&s[i]-'0'<num)cout<<num,flag=0;
cout<<s[i];
}
if(flag)cout<<num;
cout<<endl;
}
return 0;
}
B:Conveyor Belts
考虑离中间点的距离大的,然后判断各个点位在第几层,判断层数的距离就行了
注意离中间点的距离的计算就行了
#include <bits/stdc++.h>
using namespace std;
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--)
{
int N,X1,Y1,X2,Y2;
cin>>N>>X1>>Y1>>X2>>Y2;
N=N/2;
int DX1=N-X1;if(DX1<0)DX1=-DX1-1;
int DY1=N-Y1;if(DY1<0)DY1=-DY1-1;
int DX2=N-X2;if(DX2<0)DX2=-DX2-1;
int DY2=N-Y2;if(DY2<0)DY2=-DY2-1;
cout<<(int)abs(max(DX1,DY1)-max(DX2,DY2))<<endl;
}
return 0;
}
C:Restore the Array
这道题目既可以通过找规律,也可以通过模拟来进行构造
不过我没有写出来,菜是原罪,哎~~
画图!!!画图!!!画图!!!
画图看关系是真的很重要
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int num[maxn];
// int main(void)//方法一:不怎么好想
// {
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
// int T;cin>>T;
// while(T--)//取两个的间隔的max组成的数组是不可能存在(小-大-小)这种结构的,所以
// {//在两个数中每次取小的,就可以在原数组的推导中每次都可以通过取大的取出那个数,因为一个数不是比右边的大,就是比左边的大,或者相等。
// //一个数不可能同时比两边的大,所以这种方法一定可以按照顺序把每个数都取一遍。
// //对于边界的值,如果直接放上B数组的边界,这样就可以保证所有的数都可以取到,
// //边界的值可以放B数组边界的值,这样就可以保证不管是先取还是后取,都会有第一个数和最后一个数。
// int N;cin>>N;
// for(int i=0;i<N-1;i++)cin>>num[i];
// cout<<num[0]<<' ';
// for(int i=0;i<N-2;i++)cout<<min(num[i],num[i+1])<<' ';
// cout<<num[N-2]<<endl;
// }
// return 0;
// }
int main(void)
{
ios::sync_with_stdio(false);//比较容易想到
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--)
{
//不断的塞入数组进行模拟
int N;cin>>N;
for(int i=0;i<N-1;i++)cin>>num[i];
vector<int> ans;
ans.push_back(num[0]);
int cnt=1;
for(int i=1;i<N-1;i++)
{
if(cnt==i){//决定别人的时候
if(ans.back()<num[i])cnt++,ans.push_back(0);
ans.push_back(num[i]);
cnt++;
}else{//决定自己的时候
if(ans.back()<num[i])cnt++,ans.push_back(num[i]);
}
}
if(ans.size()!=N)ans.push_back(0);
for(int i=0;i<N;i++)cout<<ans[i]<<' ';
cout<<endl;
}
return 0;
}
D:Umka and a Long Flight
想像每增加一个正方形后,长度为1的正方形可以怎么变换就行了
长度为1的正方形可以怎么位移?水平方向上的移动是怎么样的,可以怎么移动?竖直方向是怎么样的?
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=50;
ll Fib[maxn];
void init()
{
Fib[0]=1;Fib[1]=1;
for(int i=2;i<maxn;i++)
Fib[i]=Fib[i-1]+Fib[i-2];
}
int main(void)
{
int T;cin>>T;
init();
while(T--)
{
ll N,X,Y;
cin>>N>>X>>Y;
int flag=N&1;
for(int i=N;i>=1;i--)if((i&1)!=flag&&X-Fib[i]>=1)X-=Fib[i];
for(int i=N;i>=1;i--)if((i&1)==flag&&Y-Fib[i]>=1)Y-=Fib[i];
if(X==1&&Y==1)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
E:Living Sequence
去掉一个数后就是九进制数,考虑每个数的组成后拆分就行了
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(void)
{
int T;cin>>T;
while(T--)//就是个十进制化为九进制而已
{
ll N;cin>>N;
ll ans=0,cnt=0;
while(N)
{
ans+=pow(10,cnt)*((N%9)>=4?((N%9)+1):(N%9));
N/=9;
cnt++;
}
cout<<ans<<endl;
}
return 0;
}
G1:Vlad and the Nice Paths (easy version)
线性dp时,考虑自己这个位置是怎么被处理的,从操作的角度来考虑,既可以被除去,也能成为一部分
多多画图,看看状态之间是怎么转移的,各种操作会导致怎么样的状态
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e2+10;
const int MOD=1e9+7;
int dp[maxn][maxn];//当前位置,有j个长度为K的序列的个数。
int C[maxn][maxn];
int num[maxn];
void init()//获取组合数的经典递推
{
for(int i=0;i<maxn;i++)
{
C[0][i]=1;
for(int j=1;j<=i;j++)
C[j][i]=(C[j-1][i-1]+C[j][i-1])%MOD;
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
init();
int T;cin>>T;
while(T--)
{
memset(dp,0,sizeof(dp));
int N,K;cin>>N>>K;
for(int i=1;i<=N;i++)cin>>num[i];
if(K==1)//注意这里后面利用到了组合数,所以这里要先特判一下
{
cout<<1<<endl;
continue;
}
dp[0][0]=1;
for(int i=1;i<=N;i++)
{
dp[i][0]=1;
for(int j=1;j<=N/K+1;j++)//对所有的情况进行更新。
{
int now=1;
for(int k=i-1;k>=1;k--)//枚举如果num[i]作为新的K位的时候的所有的可能性。
{
if(num[k]==num[i])//利用组合算进行统计。
{
now++;
if(now>=K)dp[i][j]=(dp[i][j]+(1LL*dp[k-1][j-1]*C[K-2][now-2])%MOD)%MOD;
}
}
dp[i][j]=(dp[i][j]+dp[i-1][j])%MOD;//如果num[i]这位不算,那么它的可能就是前面的可能,这里要加上
}
}
for(int i=N/K+1;i>=0;i--)//从长度最大的开始枚举。
{
if(dp[N][i])
{
cout<<dp[N][i]<<endl;
break;
}
}
}
return 0;
}
G2:Vlad and the Nice Paths (hard version)
由于不需要每个长度的,所以只要记录最长的就行了,每次对最长的进行更新
#include <bits/stdc++.h>
using namespace std;
const int maxn=5e3+10;
const int MOD=1e9+7;
int dp[maxn],Max[maxn],num[maxn];//dp记录这个位置i前(包括这个位置i)长度为Max[i]的情况的个数,
//Max[i]记录这里可以有的满足题目条件的最长的分区数。
//num记录原数组
int C[maxn][maxn];
void init()
{
for(int i=0;i<maxn;i++)
{
C[0][i]=1;
for(int j=1;j<=i;j++)
C[j][i]=(C[j-1][i-1]+C[j][i-1])%MOD;
}
}
int main(void)
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
init();
int T;cin>>T;
while(T--)
{
memset(dp,0,sizeof(dp));
memset(Max,0,sizeof(Max));
int N,K;cin>>N>>K;
for(int i=1;i<=N;i++)cin>>num[i];
dp[0]=1;
for(int i=1;i<=N;i++)
{
int now=1;
for(int j=i-1;j>=1;j--)//num[i]作为dp[i]的最后一个的情况。
{
if(num[i]==num[j])
{
now++;
if(now==K)Max[i]=Max[j-1]+1;//可以扩充的最长的
if(now>=K)
{
if(Max[i]!=Max[j-1]+1)break;//不是最长的了
dp[i]=(dp[i]+(1LL*dp[j-1]*C[K-2][now-2])%MOD)%MOD;
}
}
}
//证明i之前最长的不是i开始的,所以i这里的组合不是要的,置为0
if(Max[i]<Max[i-1])
{
dp[i]=0;
Max[i]=Max[i-1];
}
//i可以继承i-1的集合,所以直接加上dp[i-1]的情况。
//不作为最后一个考虑的情况。
if(Max[i]==Max[i-1])dp[i]=(dp[i]+dp[i-1])%MOD;
}
cout<<dp[N]<<endl;
}
return 0;
}
F不太会,就不写了
掉分了,失败的一场比赛,哎~~