期望得分:100+100+40=240

实际得分:100+0+40=140

二进制拆分、二进制前缀和

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
#define N 100001
int a[N],b[N],c[N];
const int mod=1e9+;
int suma[N][],sumb[N][];
int bit[];
void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
}
int finda(int r,int wh)
{
long long tot=;
for(int i=;i<=;i++)
if(wh&bit[i]) tot=(tot+1ll*(r-suma[r][i])*bit[i])%mod;
else tot=(tot+1ll*suma[r][i]*bit[i])%mod;
return int(tot%mod);
}
int findb(int r,int wh)
{
long long tot=;
for(int i=;i<=;i++)
if(wh&bit[i]) tot=(tot+1ll*(r-sumb[r][i])*bit[i])%mod;
else tot=(tot+1ll*sumb[r][i]*bit[i])%mod;
return int(tot%mod);
}
int main()
{
freopen("xorarray.in","r",stdin);
freopen("xorarray.out","w",stdout);
int n;
scanf("%d",&n);
int len,x;
for(int i=;i<=n;i++)
{
read(a[i]);
len=; x=a[i];
while(x) suma[i][len++]=suma[i-][len]+(x&),x/=;
for(int j=len;j<=;j++) suma[i][j]=suma[i-][j];
}
for(int i=;i<=n;i++)
{
read(b[i]);
len=; x=b[i];
while(x) sumb[i][len++]=sumb[i-][len]+(x&),x/=;
for(int j=len;j<=;j++) sumb[i][j]=sumb[i-][j];
}
bit[]=;
for(int i=;i<=;i++) bit[i]=bit[i-]<<;
c[]=a[]^b[];
for(int k=;k<=n;k++)
{
c[k]=c[k-];
c[k]=(c[k]+finda(k-,b[k]))%mod;
c[k]=(c[k]+findb(k,a[k]))%mod;
}
for(int i=;i<=n;i++) printf("%d ",c[i]);
}

60分做法:

先做一遍最小生成树

枚举两个点i,j,那么替换掉的是最小生成树上i,j路径上权值最大的边

倍增维护

时间复杂度:O(n*n*logn)

100分做法:

换一个角度,考虑被替换掉的边的贡献

边e要想被替换掉,那么点 i,j 要满足两个条件:

① 设e的两端点为u,v,i∈u,j∈v

② e的边权是连通 i,j 必经之路(最短路)上边权最大的边

怎么找这条边?——Kruscal算法

Kruscal算法每次找还没有加进去的权值最小的边,所以满足必经之路

还没有加进去的边权最小的边,是已加进去的边权最大的边,所以满足路径上边权最大

所以,设最小生成树的总权值为sum,设当前边权为w,当前边连接的两点的集合大小分别为 s1、s2

ans=(sum*n*(n-1)- 2*Σ s1*s2*w)/(n*(n-1))

n*(n-1):任意选两个点共有这些选法

Σ 前乘2:u,v 和 v,u 算不同的方案

#include<cstdio>
#include<algorithm>
#define N 20001
#define M 100001
using namespace std;
typedef long long LL;
int fa[N],siz[N];
struct node
{
int u,v,w;
}e[M];
bool cmp(node p,node q)
{
return p.w<q.w;
}
int find(int i) { return fa[i]==i ? i : fa[i]=find(fa[i]); }
int main()
{
freopen("detective.in","r",stdin);
freopen("detective.out","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
sort(e+,e+m+,cmp);
for(int i=;i<=n;i++) fa[i]=i,siz[i]=;
int u,v;
LL sum=,cnt=;
for(int i=;i<=m;i++)
{
u=find(e[i].u); v=find(e[i].v);
if(u==v) continue;
sum+=e[i].w;
cnt+=1ll*siz[u]*siz[v]*e[i].w;
fa[v]=u; siz[u]+=siz[v];
}
printf("%.2lf",sum-cnt*2.0/(n*(n-)));
}

考场上替换掉的不是 i,j 路径上权值最大的边,替换的是与i,j相连的边权最大的边,0分。

连接i,j 之后,要满足还是一颗树,去掉i,j之间的任意一条边即可

分治+DP+bitset

若点(x1,y1)能访问到点(x2,y2)

假设x1<=x2,y1<=y2

那么(x1,y1)往右下扩展,(x2,y2)往左上扩展,两个点一定在中间某一行相遇

所以可以利用分治的思想枚举相遇的那一行

如果x1和x2都在枚举的这一行的上面,那就扔到左边

如果x1和x2都在枚举的这一行的下面,那就扔到右边

左边和右边的分别继续分治下去

如果x1和x2一个在上面,一个在下面,那就判断这两个点能否在这一行相遇

能在这一行相遇,两个点一定能相遇

反之,一定不能相遇

如何判断 ?

假设当前枚举的相遇行为mid,

f[i][j][k]=0/1表示第i行第j列的点,向右下扩展,能否扩展到第mid行的第k列

g[i][j][k]=0/1表示第i行第j列的点,向左上扩展,能否扩展到第mid行的第k列

若 f[x1][y1][k] 和 g[i][j][k] 有一个k同时为true,那么两个点就可以相遇

第三维可以用bitset简化

f的转移:

预处理:f[mid][j][j]=第mid行第j列是否有障碍

倒叙枚举mid行之上的i,j,f[i][j]|=f[i][j+1],f[i][j]|=f[i+1][j]

g的转移类似,

正序枚举mid行之下的,加号改成减号即可

#include<cstdio>
#include<vector>
#include<bitset>
#define N 501
#define M 1000001
using namespace std;
int n,m;
bool mp[N][N],ans[M];
char s[N];
bitset<N>f[N][N],g[N][N];
struct node
{
int sx,sy,tx,ty,id;
};
node p;
void solve(vector<node>v,int l,int r)
{
if(l>r) return;
int mid=l+r>>;
for(int i=mid;i>=l;i--)
for(int j=m;j;j--)
{
f[i][j]=;
if(!mp[i][j]) continue;
if(i==mid) f[i][j].set(j);
else f[i][j]|=f[i+][j];
if(j!=m) f[i][j]|=f[i][j+];
}
for(int i=mid;i<=r;i++)
for(int j=;j<=m;j++)
{
g[i][j]=;
if(!mp[i][j]) continue;
if(i==mid) g[i][j].set(j);
else g[i][j]|=g[i-][j];
if(j!=) g[i][j]|=g[i][j-];
}
vector<node>vl,vr;
for(vector<node>::iterator it=v.begin();it!=v.end();it++)
{
p=*it;
if(p.tx<mid) vl.push_back(p);
else if(p.sx>mid) vr.push_back(p);
else ans[p.id]=(f[p.sx][p.sy]&g[p.tx][p.ty]).any();
}
solve(vl,l,mid-);
solve(vr,mid+,r);
}
int main()
{
freopen("boardgame.in","r",stdin);
freopen("boardgame.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%s",s+);
for(int j=;j<=m;j++) mp[i][j]= s[j]=='.' ? true : false;
}
int Q;
scanf("%d",&Q);
vector<node>v;
for(int i=;i<=Q;i++)
{
scanf("%d%d%d%d",&p.sx,&p.sy,&p.tx,&p.ty);
p.id=i;
v.push_back(p);
}
solve(v,,n);
for(int i=;i<=Q;i++) ans[i] ? puts("Yes") : puts("No");
return ;
}

考场40分双向宽搜,然而跟普通的bfs一个样

#include<cstdio>
#include<iostream>
using namespace std;
#define N 501
bool mp[N][N];
char s[N];
int n,m,rd[N][N][];
int sx,sy,tx,ty;
int vis[N][N];
int q[N*N],h,t,cnt,bl[N][N];
void read(int &x)
{
x=; char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) { x=x*+c-''; c=getchar(); }
}
int turn(int i,int j)
{
return (i-)*m+j;
}
bool bfs()
{
cnt++; h=,t=;
q[++h]=turn(sx,sy);
int now,x,y;
vis[sx][sy]=cnt;
vis[tx][ty]=cnt;
q[++t]=turn(tx,ty);
bl[sx][sy]=; bl[tx][ty]=;
while(h<=t)
{
now=q[h++];
x=(now-)/m+; y=now-(x-)*m;
if(bl[x][y]==)
{
if(mp[x+][y])
{
if(bl[x+][y]== && vis[x+][y]==cnt) return true;
if(vis[x+][y]!=cnt) vis[x+][y]=cnt,q[++t]=turn(x+,y),bl[x+][y]=;
}
if(mp[x][y+])
{
if(bl[x][y+]== && vis[x][y+]==cnt) return true;
if(vis[x][y+]!=cnt) vis[x][y+]=cnt,q[++t]=turn(x,y+),bl[x][y+]=;
}
}
else
{
if(mp[x-][y])
{
if(bl[x-][y]== && vis[x-][y]==cnt) return true;
if(vis[x-][y]!=cnt) vis[x-][y]=cnt,q[++t]=turn(x-,y),bl[x-][y]=;
}
if(mp[x][y-])
{
if(bl[x][y-]== && vis[x][y-]==cnt) return true;
if(vis[x][y-]!=cnt) vis[x][y-]=cnt,q[++t]=turn(x,y-),bl[x][y-]=;
}
}
}
return false;
}
int main()
{
freopen("boardgame.in","r",stdin);
freopen("boardgame.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%s",s+);
for(int j=;j<=m;j++) mp[i][j]=s[j]=='.' ? true : false;
}
int q;
scanf("%d",&q);
while(q--)
{
read(sx); read(sy); read(tx); read(ty);
if(!mp[sx][sy] || !mp[tx][ty]) { puts("No"); continue; }
if(sx==tx && sy==ty) { puts("Yes"); continue; }
if(tx<=sx && ty<=sy) { puts("No"); continue; }
if(bfs()) puts("Yes");
else puts("No");
}
}

2017北京国庆刷题Day6 afternoon的更多相关文章

  1. 2017北京国庆刷题Day1 afternoon

    期望得分:100+100+100=300 实际得分:100+100+100=300 T1 一道图论好题(graph) Time Limit:1000ms   Memory Limit:128MB 题目 ...

  2. 2017北京国庆刷题Day5 afternoon

    期望得分:100+60+100=260 实际得分:0+60+40=100 设图中有m个环,每个环有si条边,有k条边不在环中 ans= (2^s1 -2)*( 2^s2 -2)* (2^s3 -2)… ...

  3. 2017北京国庆刷题Day2 afternoon

    期望得分:100+100+50=250 实际得分:100+70+50=220 T1 最大值(max) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一 ...

  4. 2017北京国庆刷题Day4 afternoon

    期望得分:100+100+0=200 实际得分:5+0+0=5 每加入一个数,x的因数位置++ 注意:根号x枚举时,如果x是完全平方数,根号x会重复累计2次,要减去 考场上没减,5分 /(ㄒoㄒ)/~ ...

  5. 2017北京国庆刷题Day3 afternoon

    期望得分:100+0+30=130 实际得分:100+36.5+0=136.5 T3 一个变量写混了,丢了30.. 模拟栈 #include<cstdio> #include<cst ...

  6. 2017北京国庆刷题Day7 afternoon

    期望得分:100+30+100=230 实际得分:60+30+100=190 排序去重 固定右端点,左端点单调不减 考场上用了二分,没去重,60 #include<cstdio> #inc ...

  7. 2017北京国庆刷题Day6 morning

    期望得分:100+100+20=220 实际得分:100+100+20=220 模拟栈 #include<cstdio> #include<cstring> using nam ...

  8. 2017北京国庆刷题Day7 morning

    期望得分:100+0+100=200 实际得分:100+20+0=120 离散化搞搞 #include<cstdio> #include<iostream> #include& ...

  9. 2017北京国庆刷题Day3 morning

    期望得分:100+60+0=160 实际得分:100+30+0=130 考场上用的哈希 #include<cstdio> #include<cstring> #include& ...

随机推荐

  1. PSP阶段和WBS

    项目:PSP Daily 详情请见项目功能说明书 PSP2.1 Personal Software Process Stages 预估耗时长 Planning 计划   · Estimate · 开发 ...

  2. 用python脚本计算某一个文件的行数

    python可以统计文件的行数,你相信吗?不管你信不信反正我信了.下面我们来看一下python怎样统计文件的行数,代码很简单,我也做了注释,很简单的实现... 1 2 3 4 5 6 7 8 9 10 ...

  3. tensorboard入门

    Tensorboard tensorboard用以图形化展示我们的代码结构和图形化训练误差等,辅助优化程序 tensorboard实际上是tensorflow机器学习框架下的一个工具,需要先安装ten ...

  4. 第五周PSP &进度条

    团队项目PSP 一:表格     C类型 C内容 S开始时间 E结束时间 I时间间隔 T净时间(mins) 预计花费时间(mins) 讨论 讨论用户界面 9:27 10:42 18 57 60 分析与 ...

  5. PHP上传文件限制的大小

    修改PHP上传文件大小限制的方法 1. 一般的文件上传,除非文件很小.就像一个5M的文件,很可能要超过一分钟才能上传完.但在php中,默认的该页最久执行时间为 30 秒.就是说超过30秒,该脚本就停止 ...

  6. CSS中可以和不可以继承的属性【转】

    一.无继承性的属性 1.display:规定元素应该生成的框的类型 2.文本属性: vertical-align:垂直文本对齐 text-decoration:规定添加到文本的装饰 text-shad ...

  7. struts.xml 文件中的 namespace 属性图文详解

    namespace:名称空间.默认值是""(空字符串). 名称空间+动作名称:构成了动作的访问路径

  8. UVALive - 4975_Casting Spells

    题意很简单,给你一个字符串,要求你求出一个最长的形似于w(wr)w(wr)的最长连续子串的长度.wr表示w的逆序串. 在这里大家很容易就能想到Manacher算法求回文串.没有错,就是这个. 算法的详 ...

  9. java map的 keyset()方法

  10. ZOJ3466-The Hive II

    题意 有一个六边形格子,共 \(n\) 行,每行有 8 个位置,有一些格子不能走.求用一些环覆盖所有可走格子的方案数.\(n\le 10\) . 分析 插头dp,只不过是六边形上的,分奇数列和偶数列讨 ...