版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/84992735
解题报告
洛谷 5015 标题统计
代码(题目过水)
#include <cstdio>
#include <cctype>
using namespace std;
int ans; char c;
int main(){
while ((c=getchar())!=EOF) ans+=isalnum(c)>0;
return !printf("%d",ans);
}
洛谷 5016 龙虎斗
分析
有许多伪蒟蒻都漏掉了m号的情况,结果可能就与一等奖失之交臂,思路就是对于每一个节点判断最小值。(我朋友竟然打了二分,与一等奖失之交臂,当然,这是后话)
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
typedef long long bnt;
const int N=100010;
int n,m,choi,a[N+1],ans; bnt ans1,ans2,sum;
inline int iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans;
}
int main(){
n=iut(); for (rr int i=1;i<=n;++i) a[i]=iut();
m=iut(); rr int x=iut(); a[x]+=iut(); choi=iut();
for (rr bnt i=1;i<m;++i) ans1+=(m-i)*a[i];
for (rr bnt i=m+1;i<=n;++i) ans2+=(i-m)*a[i];
ans=m; sum=ans1<ans2?ans2-ans1:ans1-ans2;//m号初始化
for (rr bnt i=1;i<m;++i){//轩轩
ans1+=(m-i)*choi;
rr bnt t=ans1<ans2?ans2-ans1:ans1-ans2;
if (t<sum) sum=t,ans=i;
ans1-=(m-i)*choi;
}
for (rr bnt i=m+1;i<=n;++i){//凯凯
ans2+=(i-m)*choi;
rr bnt t=ans1<ans2?ans2-ans1:ans1-ans2;
if (t<sum) sum=t,ans=i;
ans2-=(i-m)*choi;
}
printf("%d",ans);
return 0;
}
洛谷 5017 摆渡车
分析(线性dp)
作为这套题最难的一道题,我差点悲剧,不过这道题是一道dp的题目,设
表示第
个同学(排序后)等车
分钟后的最短等待时间,那么在同一段的时候
要新开一段的时候
直到现在,时间复杂度已经是
,已经比较高效了,但是按照dalao的思路,可以用前缀最小值优化
的时间,优化至
代码(线性dp)
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
#define min(a,b) (((a)<(b))?(a):(b))
using namespace std;
int dp[2][201],ans=1e8,n,m,a[501];
inline int iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans;
}
int main(){
n=iut(); m=iut();
for (rr int i=1;i<=n;++i) a[i]=iut();
sort(a+1,a+1+n);
for (rr int i=1;i<=n;++i){
dp[i&1][0]=1e8;
for (rr int j=0;j<=min(a[i]-a[i-1]-m,m-1);++j) dp[i&1][0]=min(dp[i&1][0],dp[1-(i&1)][j]);
for (rr int j=1;j<2*m;++j){
dp[i&1][j]=dp[i&1][j-1];//前缀最小值
if (a[i]-a[i-1]+j>=m&&a[i]-a[i-1]+j<3*m)
dp[i&1][j]=min(dp[i&1][j],dp[1-(i&1)][a[i]-a[i-1]+j-m]);//新开一段
}
for (rr int j=0;j+a[i]-a[i-1]<2*m;++j)
dp[i&1][j]=min(dp[i&1][j],dp[1-(i&1)][j+a[i]-a[i-1]]);//同一段
for (rr int j=0;j<2*m;++j) dp[i&1][j]+=j;//无论开不开都要加等待时间
}
for (rr int i=0;i<m;++i) ans=min(ans,dp[n&1][i]);//取最小值
return !printf("%d",ans);
}
分析(斜率优化)
斜率优化与上面的线性dp迥然不同,而且对于
这么小的情况下,
太大了,不过为了培养更多的思维,在此讲一下斜率优化的方法(肯定非高效正解)
设
表示到第
时刻的总等待时间,
表示到第
时刻的同学个数,
表示在第
时刻时才发车的总等待时间
那么
然而这样肯定会超时,若使
更优秀,那么
根据一次函数
可以得到
因为
是单调递增的,所以说需要维护下凸壳
代码(斜率优化)
#include <cstdio>
#include <cctype>
#include <algorithm>
#define rr register
#define min(a,b) (((a)<(b))?(a):(b))
using namespace std;
int dp[4000201],ans=1e8,n,m,T,cnt[4000201],sum[4000201],l=1,r,q[4000201];
inline int iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans;
}
signed main(){
n=iut(); m=iut();
for (rr int i=1;i<=n;++i){
rr int x=iut(); T=max(T,x);
++cnt[x]; sum[x]+=x;
}
for (rr int i=1;i<=T+m;++i) cnt[i]+=cnt[i-1],sum[i]+=sum[i-1];
for (rr int i=0;i<m-1;++i) dp[i]=cnt[i]*i-sum[i];
for (rr int i=m-1;i<=T+m;++i){
while (l<r&&(dp[q[l+1]]-dp[q[l]]+sum[q[l+1]]-sum[q[l]])<=i*(cnt[q[l+1]]-cnt[q[l]])) ++l;//排除队头
dp[i]=cnt[i]*i-sum[i];//特殊情况
if (l<=r) dp[i]=min(dp[i],dp[q[l]]+(cnt[i]-cnt[q[l]])*i-(sum[i]-sum[q[l]]));//正常的dp方程
while (l<r&&(dp[q[r]]-dp[q[r-1]]+sum[q[r]]-sum[q[r-1]])*(cnt[i-m+1]-cnt[q[r]])>=(dp[i-m+1]-dp[q[r]]+sum[i-m+1]-sum[q[r]])*(cnt[q[r]]-cnt[q[r-1]])) --r;//排除队尾
q[++r]=i-m+1;//只有得到第i个,才能插入i-m+1
}
for (rr int i=T;i<=T+m;++i) ans=min(ans,dp[i]);
return !printf("%d",ans);
}
洛谷 5018 对称二叉树
分析
一开始我以为暴力过不了,没想到时间复杂度是
,结果成功垫底(可能是因为均摊的原因)
中序+manacher我不会
代码
#include <cstdio>
#include <cctype>
#define rr register
#define max(a,b) (((a)>(b))?(a):(b))
using namespace std;
const int N=1000000;
int n,a[N+1],lson[N+1],rson[N+1],ans;
inline signed iut(){
rr int ans=0,f=1; rr char c=getchar();
while (!isdigit(c)&&c!='-') c=getchar();
if (c=='-') c=getchar(),f=-f;
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+c-48,c=getchar();
return ans*f;
}
inline signed check(int x,int y){
if (x==-1&&y==-1) return 1;
if (a[x]!=a[y]) return 0;
return check(rson[x],lson[y])&&check(lson[x],rson[y]);
}
inline signed dfs(int x){
rr int siz=1;
if (lson[x]!=-1) siz+=dfs(lson[x]);
if (rson[x]!=-1) siz+=dfs(rson[x]);
if (check(lson[x],rson[x])) ans=max(ans,siz);
return siz;
}
signed main(){
scanf("%d",&n);
for (rr int i=1;i<=n;++i) scanf("%d",&a[i]);
for (rr int i=1;i<=n;++i) scanf("%d%d",&lson[i],&rson[i]);
dfs(1);
printf("%d",ans);
return 0;
}
后续
突然发现第一第二题全对第四题输出1就可以在广东拿一等奖了