这应该是站内相对详细的解题报告吧。
转载思路请@本人。
这一次想复杂了,第三题打了个较难的思路,导致时间过长。
第四题一开始读错题了,调了半天才 90 90 90分。
最终得分 97.5 97.5 97.5,痛失前五 Q A Q QAQ QAQ。
自己的问题,下次时间要均匀分配一些,不要想复杂了(毕竟 C S D N CSDN CSDN的题目难度大多都不高)。
听说有人抱怨考第一就作弊,其实十几分钟打完我都不信,作弊也说得过去。
有一个地方:每次测评和提交都有冷却时间(痛,太痛了)。
求求系统冷却快一点吧,好浪费时间的(特别是冷却 15 15 15秒)。
题目质量再次上升,但不多。
下次什么时候出点数据结构,让前几名的去水水?
其实可以向社会征集题目,然后经过查重和验题放进题库,不过提供题目的人通过就不能增加做题数量或参加比赛(我个人的建议)。
已知存在一个长度为 n n n的整数序列 A A A。 A A A中所有元素按照从小到达的顺序进行排序。 现在执行操作倒置一段序列。 请找到 A A A序列里的倒置子序列。
因为只有一段序列不同,所以找到最左边不相同的和最右边不相同的(与排序后相比),然后输出整段区间即可。
C + + C++ C++代码如下:
#include
using namespace std;
int a[1005]={},b[1005]={},c[1005]={},n,l=1000,r=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=c[i]=a[i];
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
if(b[i]!=a[i])b[i]=0;
else b[i]=1;
}
for(int i=1;i<=n;i++)if(b[i]==0){l=min(l,i);r=max(r,i);}
if(l==1000)l=0;
printf("%d %d\n",l,r);
return 0;
}
现在有一截楼梯,根据你的腿长,你一次能走 1 1 1级或 2 2 2级楼梯,已知你要走 n n n级楼梯才能走到你的目的楼层,请实现一个方法,计算你走到目的楼层的方案数。
典型的递推题,也是斐波那契数列,具体思路学了递推就知道了。
C + + C++ C++代码如下:
#include
using namespace std;
long long a[100];
int n;
int main()
{
a[0]=a[1]=1;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
a[i]=a[i-1]+a[i-2];
}
printf("%lld\n",a[n]);
}
小艺酱又得到了一堆括号。 括号是严格匹配的。 现在给括号进行上色。 上色有三个要求:
1、只有三种上色方案,不上色,上红色,上蓝色。
2、每对括号只有一个上色。
3、相邻的两个括号不能上相同的颜色,但是可以都不上色。
问括号上色有多少种方案?答案对 1000000007 1000000007 1000000007取模。
设 d p i , j , 0 / 1 dp_{i,j,0/1} dpi,j,0/1表示 [ i , j ] [i,j] [i,j]区间内,左右两边括号是否匹配,上色方案数。
这个方法看起来比较简单,我没认真研究,具体可以参考BMTXLRC大佬的博客。
前置知识:树形dp。
我们发现,题目给出的括号序列可以通过以下方式构成:
其中,第一种对应树中的父子关系,第二种对应树中的兄弟关系。
于是,我们可以按照上述思路,将括号序转成一棵树。
这样就变成了在树上做 d p dp dp,也就是树形 d p dp dp。
设 d p i , 0 / 1 / 2 / 3 , 0 / 1 / 2 / 3 dp_{i,0/1/2/3,0/1/2/3} dpi,0/1/2/3,0/1/2/3表示 i i i子树内,左右两边不上色/上红/上蓝的方案数。
按照题目的限制和括号序列构成方式转移即可。
C + + C++ C++代码如下:
#include
using namespace std;
int fst[100005]={},nxt[100005]={},lst[100005]={},To[100005]={};
long long dp[1005][3][3]={};
int st[100005]={};
char s[1005]={};
int n,top,cnt=0,ct=1,rt=1;
long long mod=1000000007;
void add(int x,int i)
{
if(!fst[x])
{
fst[x]=i;
lst[x]=i;
}
else
{
nxt[lst[x]]=i;
lst[x]=i;
}
}
void dfs(int x)
{
bool ok=0;
for(int i=fst[x];i;i=nxt[i])
{
int v=To[i];
dfs(v);
if(ok==0)
{
ok=1;
for(int j=0;j<=2;j++)for(int k=0;k<=2;k++)dp[x][j][k]=dp[v][j][k];
continue;
}
long long u[3][3]={};
for(int j=0;j<=2;j++)for(int k=0;k<=2;k++)u[j][k]=dp[x][j][k],dp[x][j][k]=0;
for(int j=0;j<=2;j++)
{
for(int k=0;k<=2;k++)
{
for(int l=0;l<=2;l++)
{
for(int p=0;p<=2;p++)
{
if((k==0&&l==0)||(k!=l))dp[x][j][p]=(dp[x][j][p]+u[j][k]*dp[v][l][p])%mod;
}
}
}
}
}
if(ok==0)
{
dp[x][0][1]=dp[x][0][2]=dp[x][1][0]=dp[x][2][0]=1;
}
else
{
if(x==1)
{
long long u=0;
for(int i=0;i<=2;i++)for(int j=0;j<=2;j++)
{
u=(u+dp[x][i][j])%mod;
}
dp[x][0][0]=u;
}
else
{
long long u[3][3]={};
for(int i=0;i<=2;i++)for(int j=0;j<=2;j++)u[i][j]=dp[x][i][j],dp[x][i][j]=0;
for(int i=0;i<=2;i++)
{
for(int j=0;j<=2;j++)
{
for(int k=0;k<=2;k++)
{
for(int l=0;l<=2;l++)
{
if((i==0&&j==0)||(i!=j))
if((k==0&&l==0)||(k!=l))
if((i==0&&l!=0)||(l==0&&i!=0))dp[x][i][l]=(dp[x][i][l]+u[j][k])%mod;
}
}
}
}
}
}
}
int main()
{
cin>>s;
n=strlen(s);
st[top]=1;
for(int i=0;i<n;i++)
{
if(s[i]=='(')
{
To[++cnt]=++ct;
add(st[top],cnt);
top++;
st[top]=ct;
}
else if(s[i]==')')
{
st[top]=0;
top--;
}
}
dfs(1);
printf("%lld\n",dp[1][0][0]);
return 0;
}
总是喜欢在水里嬉戏的青蛙,某天要过河拜访一位朋友。
已知河道中长满了带刺的不知名生物,能通过的路只有一条直线,长度为 L L L。
直线上随机分布着 m m m块石头。青蛙的最小跳跃距离是 s s s,最大跳跃距离是 t t t。
青蛙想要尽可能的少踩石头,那么它通过河道最少会踩到多少石头?
上面带点的句子是我补上去的,当时理解错题意了。
具体就是先离散化,然后就和一般的 d p dp dp一样了。
设 d p i dp_{i} dpi表示到达数轴点 i i i(不是输入的第 i i i个点),最少踩的石头数。
枚举区间然后转移即可。
C + + C++ C++代码如下:
#include
using namespace std;
int a[1000005]={},b[1000005]={},c[10000005]={},dp[10000005]={};
int L,m,s,t;
int main()
{
while(scanf("%d",&L)!=EOF)
{
scanf("%d%d%d",&s,&t,&m);
a[0]=0;
for(int i=1;i<=m;i++)
{
scanf("%d",&a[i]);
}
a[++m]=L;
sort(a+1,a+m+1);
for(int i=1;i<=m;i++)
{
b[i]=a[i]-a[i-1];
if(b[i]>4320)b[i]=4320;
}
for(int i=1;i<=m;i++)
{
a[i]=a[i-1]+b[i];
}
for(int i=0;i<=a[m]+20;i++)dp[i]=1e9,c[i]=0;
for(int i=1;i<=m;i++)c[a[i]]++;
dp[0]=0;
for(int i=0;i<=a[m]+20;i++)
{
for(int j=s;j<=t;j++)
{
dp[i+j]=min(dp[i+j],dp[i]+c[i]);
}
}
int ans=1e9;
for(int i=a[m];i<=a[m]+20;i++)
{
ans=min(ans,dp[i]);
}
printf("%d\n",ans);
}
return 0;
}
调调细节应该就可以了。
应该是离散化间距的问题。