123789456ye

已AFO

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;
}
posted @ 2019-08-31 08:09  123789456ye  阅读(15)  评论(0)    收藏  举报