D.
什么叫做菜得真实???
线段树常数大了点,然后被卡…我不就是用了一个struct嘛…怎么了…出题人个憨憨…
node query(int k,int l,int r)
{
if (l==r)
{
node u;
u.x=minn[k]; u.pos=l;
return u;
}
int mid=l+r>>1;
node u,v;
u=query(k<<1,l,mid);
v=query(k<<1|1,mid+1,r);
if (u.x<=v.x) return u;
else return v;
}
本来想用以上代码寻找区间最小值的位置的,我怕是个憨憨吧。然后struct返回太慢了555…
int query(int k,int l,int r)
{
if (l==r) return l;
int mid=l+r>>1;
int u,v;
if (minn[k<<1]<=minn[k<<1|1]) return query(k<<1,l,mid);
else return query(k<<1|1,mid+1,r);
}
直接这样不就好了嘛…
哎,然后看了一下排名,从rk400变成rk1200。
打个div3都能变成rk1200的除了我还有谁…
#include <bits/stdc++.h>
using namespace std;
const int N=4e5+5;
int n,x;
int a[N],sum[N];
int minn[N<<2];
void change(int k,int l,int r,int pos)
{
if (l==pos && pos==r)
{
minn[k]++;
return;
}
int mid=l+r>>1;
if (pos<=mid) change(k<<1,l,mid,pos);
else change(k<<1|1,mid+1,r,pos);
minn[k]=min(minn[k<<1],minn[k<<1|1]);
}
int query(int k,int l,int r)
{
if (l==r) return l;
int mid=l+r>>1;
int u,v;
if (minn[k<<1]<=minn[k<<1|1]) return query(k<<1,l,mid);
else return query(k<<1|1,mid+1,r);
}
int main(){
scanf("%d%d",&n,&x);
for (register int i=1; i<=n; ++i) scanf("%d",&a[i]);
int maxn=0;
for (register int i=1; i<=n; ++i)
{
change(1,0,x-1,a[i]%x);
int mul=minn[1];
int pos;
if (mul*x<i) pos=query(1,0,x-1);
else pos=0;
int now=mul*x+pos;
printf("%d\n",now);
}
return 0;
}
E.
很明显就是把每一列分开来做,但我还是不会。
暴力枚举每一列转i次后匹配的数量,那么这次需要的次数就是i+不匹配的数量。如果每次枚举一个旋转的次数,需要n^2*m的复杂度,所以推一波公式,对于某一个数来说,当旋转次数为i时它如果刚好到了它的终止位置,那么就sum[i]++。这样复杂度是nm。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,m,x,ans;
int sum[N];
vector<int>a[N];
inline int solve(int x)
{
for (register int i=0; i<n; ++i) sum[i]=0;
for (register int i=1; i<=n; ++i)
if (a[i][x]%m==x%m && a[i][x]<=n*m)
{
int hang=a[i][x]/m;
if (a[i][x]%m!=0) hang++;
sum[(n+i-hang)%n]++;
}
int minn=2e9;
for (register int i=0; i<n; ++i) minn=min(minn,i+n-sum[i]);
return minn;
}
int main(){
scanf("%d%d",&n,&m);
for (register int i=1; i<=n; ++i) a[i].push_back(0);
for (register int i=1; i<=n; ++i)
for (register int j=1; j<=m; ++j) scanf("%d",&x),a[i].push_back(x);
for (register int i=1; i<=m; ++i) ans+=solve(i);
printf("%d\n",ans);
return 0;
}
F.
F题也不会…
找到直径的两个端点以后,把直径标记出来,然后在树中找一个离直径最远的点即可。直径题目做了那么多还是不会…
菜得真实…
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,u,v,p,ans;
int d[N],dep[N];
bool f[N];
int cnt,head[N];
struct edge{int next,to;}e[N<<1];
inline void add(int u,int v)
{
cnt++;
e[cnt].next=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs(int u,int fa,int now)
{
d[u]=now;
if (d[u]>ans) ans=d[u],p=u;
for (register int i=head[u]; i; i=e[i].next) if (e[i].to!=fa) dfs(e[i].to,u,now+1);
}
void dfs2(int u,int fa,int now)
{
f[u]=true;
for (register int i=head[u]; i; i=e[i].next)
if (d[e[i].to]+now+1==ans) dfs2(e[i].to,u,now+1);
}
void dfs3(int u,int fa)
{
for (register int i=head[u]; i; i=e[i].next)
if (e[i].to!=fa)
{
if (f[e[i].to]) {dep[e[i].to]=0; dfs3(e[i].to,u);}
else {dep[e[i].to]=dep[u]+1; dfs3(e[i].to,u);}
}
}
int main(){
scanf("%d",&n);
for (register int i=1; i<n; ++i)
{
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs(1,0,0);
ans=0;
u=p;
dfs(p,0,0);
v=p;
dfs2(p,0,0);
dfs3(p,0);
int maxn=-1,id;
for (register int i=1; i<=n; ++i)
if (i!=u && i!=v)
{
if (maxn<dep[i]) maxn=dep[i],id=i;
}
printf("%d\n",ans+maxn);
printf("%d %d %d\n",u,v,id);
return 0;
}