VK Cup 2016 - Round 3
链接
A. Bear and Colors
水题,直接扫两遍就好了
B. Bear and Two Paths
构造题。考虑 是一个环凑一凑发现不合法。所以一定是 。
可以发现只要 一定可以放两个三元环,否则无解。
C. Levels and Regions
一通推式子之后有:
然后就是经典斜率优化。
复杂度 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 200010
#define db double
using namespace std;
int t[N];
db s[N],p[N],sp[N],f[N],g[N],h[N];
int q[N],ql,qr;
db slope(int x,int y){return (h[y]-h[x])/(s[y]-s[x]);}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&t[i]),p[i]=1.0/t[i];
for(int i=1;i<=n;i++) p[i]+=p[i-1],s[i]=s[i-1]+t[i],sp[i]=sp[i-1]+s[i]/t[i];
for(int i=1;i<=n;i++) g[i]=sp[i];
// for(int i=1;i<=n;i++) printf("%.6lf %.6lf %.6lf\n",p[i],s[i],sp[i]);
for(int _=2;_<=k;_++)
{
ql=0,qr=0;q[ql]=0;
for(int i=1;i<=n;i++)
{
while(ql<qr && slope(q[ql],q[ql+1])<p[i]) ql++;
f[i]=h[q[ql]]-s[q[ql]]*p[i]+sp[i];
h[i]=g[i]-sp[i]+s[i]*p[i];
// printf("%d,%.6lf\n",q[ql],f[i]);
while(ql<qr && slope(q[qr-1],q[qr])>=slope(q[qr],i)) qr--;
q[++qr]=i;
}
// puts("");
for(int i=1;i<=n;i++) g[i]=f[i],f[i]=0;
}
printf("%.10lf\n",g[n]);
return 0;
}
D. Bearish Fanpages
赛时想了一个 ,结果被卡了。。。
后来发现自己是个傻子,考虑每个点的贡献挂到它的父亲上面,然后父亲挑选最小最大的点加上自己的权值后放入总的 set。
直接维护差值,复杂度 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<cassert>
#include<cmath>
#define N 100010
#define ll long long
using namespace std;
ll t[N],g[N];int f[N],deg[N],n,q;
struct node{
int x;ll y;
node(int X=0):x(X),y(g[x]){}
node(int X,ll Y):x(X),y(Y){}
bool operator <(const node a)const{return y==a.y?x<a.x:y<a.y;}
};
node operator +(const node a,ll v){return node(a.x,a.y+v);}
set<node>s,b[N];
set<int>h[N];
ll calc(int x){return t[x]-(deg[x]+1)*(t[x]/(deg[x]+2));}
ll delta_calc(int x,int y)
{
ll v=calc(x);deg[x]+=y;
v-=calc(x);deg[x]-=y;
return v;
}
ll one(int x){return t[x]/(deg[x]+2);}
ll delta_one(int x,int y)
{
ll v=one(x);deg[x]+=y;
v-=one(x);deg[x]-=y;
return v;
}
void bdel(int x){if(!b[x].empty()) s.erase(*b[x].begin()+one(x)),s.erase(*b[x].rbegin()+one(x));}
void badd(int x){if(!b[x].empty()) s.insert(*b[x].begin()+one(x)),s.insert(*b[x].rbegin()+one(x));}
void del(int x){bdel(f[x]),b[f[x]].erase(x),badd(f[x]);}
void add(int x){bdel(f[x]),b[f[x]].insert(x),badd(f[x]);}
void chg(int x,ll v){del(x),g[x]-=v,add(x);}
void chg_edge(int x,int v)
{
chg(x,delta_calc(x,v));
ll d=delta_one(x,v);
chg(f[x],d);
bdel(x),deg[x]+=v,badd(x);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",&t[i]);
for(int i=1;i<=n;i++) scanf("%d",&f[i]),deg[f[i]]++,h[f[i]].insert(i);
for(int i=1;i<=n;i++) g[i]+=calc(i),g[f[i]]+=one(i);
for(int i=1;i<=n;i++) b[f[i]].insert(i);
for(int i=1;i<=n;i++) badd(i);
while(q --> 0)
{
int op,x,y;scanf("%d",&op);
if(op==3) printf("%lld %lld\n",s.begin()->y,s.rbegin()->y);
else if(op==2) scanf("%d",&x),printf("%lld\n",g[x]+one(f[x]));
else
{
scanf("%d%d",&x,&y);
del(x);
chg(f[x],one(x)),chg(y,-one(x));
h[f[x]].erase(x);
chg_edge(f[x],-1);chg_edge(y,1);
h[y].insert(x);
f[x]=y;add(x);
}
}
return 0;
}
E. Bear and Destroying Subtrees
看到期望题输出实数就要注意了。。。
点 深度大于等于 的概率。
设置一个阈值 ,有:
注意到当 的时候贡献可以忽略。所以只要处理一个点向上 个点即可。
复杂度 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 500010
#define M 51
#define db double
using namespace std;
int fa[N];db f[N][M];
int main()
{
int n=1,q;
scanf("%d",&q);
while(q --> 0)
{
int op,x;scanf("%d%d",&op,&x);
if(op==2)
{
db res=0;
for(int j=1;j<M;j++) res+=f[x][j];
printf("%.10lf\n",res);
}
else
{
++n;fa[n]=x;f[n][0]=1;
int u=x,p=n;db v=1;
for(int d=1;d<M && u;d++,p=u,u=fa[u])
{
db w=f[u][d];
f[u][d]=1-(1-w)/v*(1-0.5*f[p][d-1]);
v=1-0.5*w;
}
}
}
return 0;
}
F. Bears and Juice
考虑信息论,总共 只熊, 天,最多能睡 头熊,那么这里的信息量是 。
实际上答案就是这个。
注意 不是质数,所以要手动约分分子分母。
复杂度 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 100010
#define ui unsigned int
using namespace std;
ui gcd(ui x,ui y){return y==0?x:gcd(y,x%y);}
void div(vector<ui>&a,vector<ui>&b){for(ui &i:a) for(ui &j:b){ui g=gcd(i,j);i/=g,j/=g;}}
ui f[N];
int main()
{
int n,p,q;
ui ans=0;
scanf("%d%d%d",&n,&p,&q);p=min(p,n-1);
for(int j=0;j<=p;j++)
{
vector<ui>a,b;
for(int i=1;i<=j;i++) a.push_back(n-i+1),b.push_back(i);
div(a,b);f[j]=1;
for(int i=0;i<j;i++) f[j]*=a[i];
}
for(ui i=1;i<=q;i++)
{
ui res=0,pi=1;
for(int j=0;j<=p;j++) res+=f[j]*pi,pi*=i;
ans^=res*i;
}
cout<<ans;
return 0;
}
G. Choosing Ads
经典问题。
考虑主元素定理:每次选择两个不同的数消掉,最后主元素一定被剩下。
那么这里就扩展一下:假设至少出现 ,那么每次选择 个不同的数消掉,最后至少出现 的数一定被留下。
合并时暴力将一边的元素扔到另一边即可。
复杂度 。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 300010
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<int,int> pi;
int p;
struct node{
int c;
pi v[5];
pi& operator [](int x){return v[x];}
}t[N<<2];
int tag[N<<2];
node operator +(node a,pi x)
{
// if(x.fi==0) throw;
for(int i=0;i<a.c;i++) if(a[i].fi==x.fi){a[i].se+=x.se;return a;}
if(a.c<p){a[a.c++]=x;return a;}
int q=0;
for(int i=1;i<a.c;i++) if(a[i].se<a[q].se) q=i;
if(a[q].se<x.se) swap(a[q],x);
for(int i=0;i<a.c;i++) a[i].se-=x.se;
return a;
}
node operator +(node a,node b){for(int i=0;i<b.c;i++) a=a+b[i];return a;}
void setg(int u,int c,int v){t[u].c=1,tag[u]=v,t[u][0]=mp(v,c);}
void push(int u,int l,int r)
{
if(!tag[u]) return;
int mid=(l+r)>>1;
setg(u<<1,mid-l+1,tag[u]);
setg(u<<1|1,r-mid,tag[u]);
tag[u]=0;
}
int a[N];
void build(int u,int l,int r)
{
if(l==r){t[u][0]=mp(a[l],1);t[u].c=1;return;}
int mid=(l+r)>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
t[u]=t[u<<1]+t[u<<1|1];
}
void insert(int u,int l,int r,int L,int R,int v)
{
if(L<=l && r<=R){setg(u,r-l+1,v);return;}
int mid=(l+r)>>1;push(u,l,r);
if(L<=mid) insert(u<<1,l,mid,L,R,v);
if(R>mid) insert(u<<1|1,mid+1,r,L,R,v);
t[u]=t[u<<1]+t[u<<1|1];
}
node qry(int u,int l,int r,int L,int R)
{
if(L<=l && r<=R) return t[u];
int mid=(l+r)>>1;push(u,l,r);
if(R<=mid) return qry(u<<1,l,mid,L,R);
else if(L>mid) return qry(u<<1|1,mid+1,r,L,R);
return qry(u<<1,l,mid,L,R)+qry(u<<1|1,mid+1,r,L,R);
}
int main()
{
int n,m;
scanf("%d%d%d",&n,&m,&p);p=100/p;
// printf("%d\n",p);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
for(int i=1;i<=m;i++)
{
int op,l,r,w;scanf("%d%d%d",&op,&l,&r);
if(op==1) scanf("%d",&w),insert(1,1,n,l,r,w);
else
{
node a=qry(1,1,n,l,r);
printf("%d ",a.c);
for(int j=0;j<a.c;j++) printf("%d ",a[j].fi);puts("");
}
}
return 0;
}
本文来自博客园,作者:Flying2018,转载请注明原文链接:https://www.cnblogs.com/Flying2018/p/CF643.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理