t1 浇花
考场代码:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dwn(i,a,b) for(int i=a;i>=b;--i)
#define X (c^48)
#define C c=getchar()
using namespace std;
template <typename T> void inline rd(T&x){char c;int f=1;while(!isdigit(C))if(c=='-')f=-1;x=X;while(isdigit(C))x=x*10+X;x*=f;}
void wr(int x){if(x<0){putchar('-');x=-x;}if(x>9)wr(x/10);putchar(x%10+'0');}
#define ll long long
#define N 1010
int n,minn=0,pos=0,min_h=1e9;
int mincf[N][N],ans[N],h[N],cf[N];
int main()
{
freopen("read.txt","r",stdin);
rd(n);
rep(i,1,n)
{
rd(h[i]);
if(h[i]<min_h)
{
min_h=h[i];
pos=i;
}
cf[i]=h[i]-h[i-1];
ans[i]++;
}
rep(i,1,n)
{
if(cf[i]>0)
ans[i-1]++;
else ans[i]++;
}
rep(i,1,n)
{
if(h[i]<h[i-1] && h[i]<h[i+1])ans[i]++;
else if(h[i-1]<h[i] && h[i-1]<h[i+1])ans[i-1]++;
else if(h[i+1]<h[i] && h[i+1]<h[i-1])ans[i+1]++;
}
rep(i,1,n)
{
if(h[i]<h[i-1] && h[i]<h[i+1] && h[i]<h[i+2])ans[i]++;
else if(h[i-1]<h[i] && h[i-1]<h[i+1] && h[i-1]<h[i+2])ans[i-1]++;
else if(h[i+1]<h[i] && h[i+1]<h[i-1] && h[i+1]<h[i+2])ans[i+1]++;
else if(h[i+2]<h[i] && h[i+2]<h[i-1] && h[i+2]<h[i+1])ans[i+2]++;
}
if(pos==1)ans[1]=n;
if(pos==n)ans[n]==n;
ans[pos]++;
/*rep(l,1,n)//当前区间长度
rep(i,1,n)//当前区间起点
for(int j=i+l;i<=n;++i)//终点
{
anss[i][j]=min(h[i],h[j]);
}
*/
rep(i,1,n)
printf("%d ",ans[i]);
return 0;
}
正解:
思路:
根据乘法原理,一个数被统计的次数==(i-l[i])* (r[i]-r)
l[i]:i左边第一个<i的数
r[i]:i左边第一个<i的数
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dwn(i,a,b) for(int i=a;i>=b;--i)
#define X (c^48)
#define C c=getchar()
using namespace std;
template <typename T> void inline rd(T&x){char c;int f=1;while(!isdigit(C))if(c=='-')f=-1;x=X;while(isdigit(C))x=x*10+X;x*=f;}
void wr(int x){if(x<0){putchar('-');x=-x;}if(x>9)wr(x/10);putchar(x%10+'0');}
#define ll long long
#define N 1000010
int n;
int a[N],l[N],r[N];
map<int,long long>h;
int main()
{
freopen("read.txt","r",stdin);
rd(n);
rep(i,1,n)
{
rd(a[i]);
l[i]=i-1,r[i]=i+1;//注意要初始化
}
rep(i,1,n)
while(a[l[i]]>a[i])
l[i]=l[l[i]];//更新l[i]
dwn(i,n,1)
while(a[r[i]]>a[i])
r[i]=r[r[i]];//更新r[i]
rep(i,1,n)
printf("%lld ",(long long)(i-l[i])*(r[i]-i));
//注意一定要转long long!!!!乘积有可能会爆掉int
return 0;
}
t2 ABCDEF
思路:
(a × b + c) ÷ d – e = f 变形成(a * b+c)==(f+e) * d,省去除法(浮点数懒得判断)
使用map<int,long long>h,哈希表来做等式两边的中转
十年OI一场空,不开long long 见祖宗
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dwn(i,a,b) for(int i=a;i>=b;--i)
#define X (c^48)
#define C c=getchar()
using namespace std;
template <typename T> void inline rd(T&x){char c;int f=1;while(!isdigit(C))if(c=='-')f=-1;x=X;while(isdigit(C))x=x*10+X;x*=f;}
void wr(int x){if(x<0){putchar('-');x=-x;}if(x>9)wr(x/10);putchar(x%10+'0');}
#define ll long long
#define N 110
int n;
map<int,long long>h;
int x[N];
ll ans;
int main()
{
freopen("readda.txt","r",stdin);
rd(n);
rep(i,1,n)rd(x[i]);
rep(a,1,n)
rep(b,1,n)
rep(c,1,n)
h[x[a]*x[b]+x[c]]++;
rep(d,1,n)
rep(e,1,n)
rep(f,1,n)
{
if(x[d]==0)continue;
ans+=h[(x[f]+x[e])*x[d]];
}
printf("%lld",ans);
return 0;
}
t3奶牛健美操
题目大意:
给定一棵树,可以删掉s条边,求删掉后森林中所有树直径的最大值的最小值
思路:
最大值最小,典型的二分答案
此题我们二分树的直径,每次二分DFS一次,对于每个节点统计出所有子树删边后的dis,排序,贪心删掉最大的,直到最大的两个子树相加不会超过二分的答案为止
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dwn(i,a,b) for(int i=a;i>=b;--i)
#define X (c^48)
#define C c=getchar()
using namespace std;
template <typename T> void inline rd(T&x){char c;int f=1;while(!isdigit(C))if(c=='-')f=-1;x=X;while(isdigit(C))x=x*10+X;x*=f;}
const int N=1e5+10;
struct Edge{int v,next;}e[N<<1];
int n,s,tot,ans,head[N],a[N],f[N];
void add(int x,int y){e[++tot].v=y;e[tot].next=head[x];head[x]=tot;}
void dfs(int u,int fa,int limit)
{
int cnt=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==fa)continue;
dfs(e[i].v,u,limit);
}
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==fa)continue;
a[++cnt]=f[v]+1;
}
sort(a+1,a+cnt+1);
while(cnt && a[cnt]+a[cnt-1]>limit)
cnt--,ans++;
f[u]=a[cnt];
}
inline bool check(int x)
{
ans=0;
dfs(1,0,x);
return ans<=s;
}
int main()
{
freopen("input.txt","r",stdin);
rd(n),rd(s);
rep(i,1,n-1)
{
int u,v;rd(u),rd(v);
add(u,v),add(v,u);
}
int l=0,r=n,mid,ans;
while(l<=r)
{
mid=l+r>>1;
if(check(mid))
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
printf("%d",ans);
return 0;
}
分数与总结:
t1 0pts
t2 30pts
t3 0pts
考试的时候心态崩了,t1、t3都写挂了,只拿了t2的暴力分……我skr zz
暴露出的问题:
- map
- 单调栈
- 树形DP+二分