2019暑假记录下
8.26 Day1
爆零祭,跑8圈预定祭,被Tham D祭
T1 书堆(a)
题意:bzoj 2048
题解:可看出\(ans=m* \sum_{i=1}^{n}{\frac{1}{2i}}\)(虽然我这个物理菜狗并没有看出来)
然后有一个玄学的调和级数近似公式
$$\sum_{i=1}^{n}{\frac{1}{i}}=\ln(n)+\gamma$$
其中\(\gamma\)为欧拉常数,约等于\(0.57721566\)(背了就行)
注意这只是一个近似公式
复杂度\(O(1)\sim O(n)\)
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
long long n,m,ans;
long double f=0;
scanf("%lld%lld",&n,&m);
if(n<=1e7)
for(int i=2;i<=n<<1;i+=2) f+=1.0/i;
else f=(log(n)+0.5772156649)/2;
ans=f*m-1e-6;
printf("%lld\n",ans);
return 0;
}
T2 最长距离 b
题意:bzoj 1295
题解:对于每个点跑一遍spfa求出以当前点为起点符合条件的路径(即障碍物数小于等于T)
复杂度:\(O(n^2m^2+nm*spfa)\)
#include<bits/stdc++.h>
using namespace std;
#define mp make_pair
int n,m,t,ans,G[32][32],vis[32][32],dis[32][32];
int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
char s[40];
queue<pair<int,int> > q;
void spfa(int sx,int sy)
{
memset(vis,0,sizeof(vis));
memset(dis,0x7f,sizeof(dis));
vis[sx][sy]=1;
dis[sx][sy]=G[sx][sy];
q.push(mp(sx,sy));
while(!q.empty())
{
int tx=q.front().first,ty=q.front().second;
vis[tx][ty]=0;
q.pop();
for(int i=0;i<4;++i)
{
int tmpx=tx+d[i][0],tmpy=ty+d[i][1];
if(tmpx&&tmpy&&tmpx<=n&&tmpy<=m)
{
if(dis[tmpx][tmpy]>dis[tx][ty]+G[tmpx][tmpy])
{
dis[tmpx][tmpy]=dis[tx][ty]+G[tmpx][tmpy];
if(!vis[tmpx][tmpy])
q.push(mp(tmpx,tmpy)),vis[tmpx][tmpy]=1;
}
}
}
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(dis[i][j]<=t)
{
int tmp=(sx-i)*(sx-i)+(sy-j)*(sy-j);
if(tmp>ans) ans=tmp;
}
}
int main()
{
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=n;++i)
{
scanf("%s",s+1);
for(int j=1;j<=m;++j)
G[i][j]=(s[j]=='0'?0:1);
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
spfa(i,j);
printf("%.6lf",sqrt(ans));
return 0;
}
T3 聚会 c
题意:bzoj 1832
题解:一开始以为是个图就自闭了,后面突然发现是棵树然后赶紧写掉,结果分类讨论写挂了直接枚举lca即可
复杂度:\(O(n\log n)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
struct Edge
{
int fr,to;
}eg[maxn<<1];
int head[maxn],edgenum,n,m,deep[maxn],fa[maxn][20],ln;
inline void add(int fr,int to)
{
eg[++edgenum]=(Edge){head[fr],to};
head[fr]=edgenum;
}
inline void dfs(int rt,int fat,int dep)
{
deep[rt]=dep;
fa[rt][0]=fat;
for(int i=head[rt];i;i=eg[i].fr)
if(eg[i].to!=fat) dfs(eg[i].to,rt,dep+1);
}
inline int lca(int x,int y)
{
if(deep[x]<deep[y]) swap(x,y);
int dist=deep[x]-deep[y];
for(int i=0;i<=ln;++i)
if((1<<i)&dist) x=fa[x][i];
if(x==y) return x;
for(int i=ln;i>=0;--i)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
inline int getdis(int x,int y)
{
return deep[x]+deep[y]-2*deep[lca(x,y)];
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%d%d",&n,&m);
int a,b,c;
for(int i=1;i<n;++i)
{
scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
dfs(1,0,0);
ln=log(n)/log(2)+1;
for(int i=1;i<=ln;++i)
for(int j=1;j<=n;++j)
fa[j][i]=fa[fa[j][i-1]][i-1];
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&a,&b,&c);
int l1=lca(a,b),l2=lca(a,c),l3=lca(b,c);
if(l1==l2) printf("%d %d\n",l3,getdis(l3,a)+getdis(l3,b)+getdis(l3,c));
else if(l1==l3) printf("%d %d\n",l2,getdis(l2,a)+getdis(l2,b)+getdis(l2,c));
else if(l2==l3) printf("%d %d\n",l1,getdis(l1,a)+getdis(l1,b)+getdis(l1,c));
}
return 0;
}
T4 地精部落 d
题意:bzoj 1925
题解:神仙dp。题解直接度娘吧。代码奇短好评
复杂度:\(O(n^2)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 5005
int dp[maxn][maxn];
int main()
{
int n,mod,ans=0;
scanf("%d%d",&n,&mod);
dp[1][1]=dp[2][2]=1;
for(int i=3;i<=n;++i)
{
for(int j=2;j<=i;++j)
dp[i][j]+=dp[i][j-1]+dp[i-1][i-j+1],dp[i][j]%=mod;
}
for(int i=2;i<=n;++i)
ans+=dp[n][i],ans%=mod;
ans<<=1;
ans%=mod;
printf("%d\n",ans);
return 0;
}
T5 纪念品盒 e
题意:bzoj 4368
题解:贪心。也是度娘吧。
复杂度:\(O(n)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 10000005
int l[maxn],r[maxn],pos[maxn],n,k,L;
long long LL[maxn],RR[maxn];
int main()
{
freopen("e.in","r",stdin);
freopen("e.out","w",stdout);
scanf("%d%d%d",&n,&k,&L);
for(int i=1;i<=n;++i)
scanf("%d",&pos[i]);
int lenl=0,lenr=0;
for(int i=1;i<=n;++i)
{
if(!pos[i]) continue;
if((pos[i]<<1)<=L) l[++lenl]=pos[i];
else r[++lenr]=pos[i];
}
for(int i=1;i<=lenr>>1;++i) swap(r[i],r[lenr-i+1]);
for(int i=1;i<=lenl;++i)
{
if(i<=k) LL[i]=l[i]<<1;
else LL[i]=LL[i-k]+(l[i]<<1);
}
for(int i=1;i<=lenr;++i)
{
if(i<=k) RR[i]=(L-r[i])<<1;
else RR[i]=RR[i-k]+((L-r[i])<<1);
}
long long ans=LL[lenl]+RR[lenr];
for(int i=0;i<k;++i)
ans=min(ans,LL[lenl-i]+RR[max(0,lenr+i-k)]+L);
printf("%lld\n",ans);
return 0;
}
8.30
爆零
A ricehub 米道
题意:给定\(x_{i}\),每个点有一堆谷子。定义两点间费用为坐标差绝对值。已知费用小于等于B,求最大能收到多少谷子。\(i\leq 10^5,x_{i}\leq 10^9,B\leq 10^{18}\)
题解:想着二分结果一开始去重了就半天没想出来
设两个指针\(l,r\),每次l+1,r移动到能移动到的最远处。费用可以\(O(1)\)的算出。
复杂度:\(O(n)\)
#include<bits/stdc++.h>
using namespace std;
long long pos[100005];
int l,r,ans;
long long sum[100005],B;
inline bool check(int x)
{
int mid=(l+x)>>1;
long long tmp1=sum[l-1]-sum[mid-1]+(mid-l)*pos[mid];
long long tmp2=sum[x]-sum[mid]-(x-mid)*pos[mid];
return tmp1+tmp2<=B;
}
int main()
{
int R,L;
scanf("%d%d%lld",&R,&L,&B);
for(int i=1;i<=R;++i)
{
scanf("%lld",&pos[i]);
sum[i]=sum[i-1]+pos[i];
}
l=1,r=1,ans=-1;
for(;l<R;l++)
{
while(r<R&&check(r+1)) r++;
ans=max(ans,r-l+1);
}
printf("%d\n",ans);
return 0;
}
B 块的计数
题意:给定一棵n个点的树,问将其划分为相同点数的联通块的方案数。(只要点数相同就算一种)。\(n\leq 10^6\)
题解:只要一个节点的size是点数的倍数它就可以作为块的根。虽然我现在都还不会证
复杂度:\(O(n\log n)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
struct Edge
{
int fr,to;
Edge(){}
Edge(int a,int b):fr(a),to(b){}
}eg[maxn<<1];
int head[maxn],edgenum,size[maxn],buc[maxn];
inline void add(int fr,int to)
{
eg[++edgenum]=Edge(head[fr],to);
head[fr]=edgenum;
}
inline void dfs(int rt,int fa)
{
size[rt]=1;
for(int i=head[rt];i;i=eg[i].fr)
{
if(eg[i].to==fa) continue;
dfs(eg[i].to,rt);
size[rt]+=size[eg[i].to];
}
++buc[size[rt]];
}
int main()
{
int cnt=0,n,a,b;
scanf("%d",&n);
for(int i=1;i<n;++i)
scanf("%d%d",&a,&b),add(a,b),add(b,a);
dfs(1,0);
for(int i=1;i<=n;++i)
{
for(int j=2*i;j<=n;j+=i)
buc[i]+=buc[j];
if(i*buc[i]==n) ++cnt;
}
printf("%d\n",cnt);
return 0;
}
C 缓存交换
题意:有一个容量有限的箱子,你要找东西先从箱子里找,如果箱子里没有就在外面找并将其放进箱子,并扔出一个箱子内的物品。给定长度为n的寻找序列\(x_{i}\),求箱子里找不到的最小次数。\(n\leq 10^{5},x_{n}\leq 10^9\)
题解:考虑贪心。把箱子内的下一个离现在所处位置最远的那个物品扔掉。这么做显然不会更差
复杂度:\(O(n\log n)\)
#include<bits/stdc++.h>
using namespace std;
priority_queue<int>q;
#define maxn 100005
int n,m,a[maxn],b[maxn],last[maxn],nxt[maxn],cnt,ans,chose[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n);
int k=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(b+1,b+1+k,a[i])-b;
nxt[last[a[i]]]=i;
last[a[i]]=i;
}
for(int i=1;i<=k;++i)
nxt[last[i]]=i+n,a[n+i]=i;
for(int i=1;i<=n;i++)
{
while(!q.empty()&&!chose[a[q.top()]]) q.pop();
if(chose[a[i]])
{
q.push(nxt[i]);
continue;
}
if(cnt<m)
{
chose[a[i]]=1;
cnt++;
ans++;
q.push(nxt[i]);
continue;
}
chose[a[q.top()]]=0;
ans++;
q.pop();
q.push(nxt[i]);
chose[a[i]]=1;
}
printf("%d\n",ans);
return 0;
}
D 动物园
题意:传送门
题解:考虑状压。设\(dp[i][j]\)表示以i起始,状态为j的能最大满足的小朋友数量。
$$dp[i][j]=max(dp[i-1][(j& 15)<<1],dp[i-1][(j& 15)<<1|1]+num[i][j]$$
其中与15是用来递推状态的,num数组是预处理好的,表示以i起始状态为j能满足多少个小朋友。
复杂度:\(O(n*2^{10})\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 50005
int n,m,ans,num[maxn][32],dp[maxn][32];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i)
{
int tmp,st,tf,tl,fear=0,love=0;
scanf("%d%d%d",&st,&tf,&tl);
for(int j=1;j<=tf;++j)
{
scanf("%d",&tmp);
tmp=(tmp-st+n)%n;
fear|=(1<<tmp);
}
for(int j=1;j<=tl;++j)
{
scanf("%d",&tmp);
tmp=(tmp-st+n)%n;
love|=(1<<tmp);
}
for(int j=0;j<32;++j)
if(j&fear||(~j&love)) ++num[st][j];
}
for(int i=0;i<32;++i)
{
memset(dp[0],128,sizeof(dp[0]));
dp[0][i]=0;
for(int j=1;j<=n;++j)
for(int k=0;k<32;++k)
dp[j][k]=max(dp[j-1][(k&15)<<1],dp[j-1][(k&15)<<1|1])+num[j][k];
if(ans<dp[n][i]) ans=dp[n][i];
}
printf("%d\n",ans);
return 0;
}
E 飞机路线
题意:给定无向图,可使最多k条线权值变为0,求最短路。\(n\leq 10^4,m\leq 5*10^4,k\leq 10\)
题解:有一种把dis开到二维跑最短路的。不过标程是分层图。建立(k+1)张图,图间连0权边,图间终点连0权边(防止毒瘤数据)然后直接跑最短路。
复杂度:\(O(nk\log n)\)
#include<bits/stdc++.h>
using namespace std;
#define maxn 110005
#define pa pair<int,int>
#define mp make_pair
struct Edge
{
int fr,to,val;
Edge(){}
Edge(int _fr,int _to,int _val):fr(_fr),to(_to),val(_val){}
}eg[maxn*20];
int head[maxn],edgenum,dis[maxn];
inline void add(int fr,int to,int val)
{
eg[++edgenum]=Edge(head[fr],to,val);
head[fr]=edgenum;
}
priority_queue<pa,vector<pa>,greater<pa> >q;
void dijskra(int st)
{
memset(dis,0x3f,sizeof(dis));
dis[st]=0;
q.push(mp(dis[st],st));
while(!q.empty())
{
int dist=q.top().first,id=q.top().second;
q.pop();
for(int i=head[id];i;i=eg[i].fr)
{
if(dis[eg[i].to]>dist+eg[i].val)
{
dis[eg[i].to]=dist+eg[i].val;
q.push(mp(dis[eg[i].to],eg[i].to));
}
}
}
}
int main()
{
//freopen("3.in","r",stdin);
int n,m,k,s,t;
scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);
++s,++t;
int a,b,c;
for(int i=1;i<=m;++i)
{
cin>>a>>b>>c;
++a,++b;
add(a,b,c),add(b,a,c);
for(int j=1;j<=k;++j)
{
add(a+j*n,b+j*n,c);
add(b+j*n,a+j*n,c);
add(a+(j-1)*n,b+j*n,0);
add(b+(j-1)*n,a+j*n,0);
}
}
dijskra(s);
printf("%d\n",dis[t+k*n]);
return 0;
}
There is a negligible beginning in all great action and thought.

浙公网安备 33010602011771号