8.22总结

函数变化

考试最后关头,我才发现T1是有规律的,哭~
写下一个暴力程序,打表后,你可以发现前n-1项中第i项的答案为\(2^{i-1}\),第n项为\(2^{n-1}-1\),n以后项的答案为前n项的和,就可以\(O(n)\)解决问题了。

AC Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read()
{
	ll x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const int N=1e6+5;
const int mod=1e9+9;
ll n,m,f[N];

int main()
{
	n=read(),m=read();
	ll sum=1;f[1]=1;
	for(int i=2;i<=n;i++)
	{
		f[i]=f[i-1]*2%mod;
		if(i==n)f[i]-=1;
		sum=(sum+f[i])%mod;
	}
	for(int i=n+1;i<=m;i++)
	{
		f[i]=sum;
		sum=((sum-f[i-n]+f[i])%mod+mod)%mod;
	}
	printf("%lld\n",f[m]);
	return 0;
}

刺客信条

\(solution\)

二分+并查集
二分红衣教徒的影响范围,然后枚举每个红衣教徒,看是否覆盖上下左右边界,再然后看红衣教徒之间是否相交,最后看上下边界和左右边界是否联通,如果联通则r=mid,否则l=mid;

AC Code
#include<bits/stdc++.h>
using namespace std;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const double eps=1e-8;
int x,y,n,fa[2005];
int num[2005][2];
struct ww{
	int x,y;
}a[2005];

int find(int x)
{
	return fa[x]==x?x:fa[x]=find(fa[x]);
}

bool check(double s)
{
	int tmp1=0,tmp2=0;
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=n;i++)
	{
		if(a[i].y-s<eps||a[i].x+s>x+eps)
			num[++tmp1][0]=i;
		if(a[i].x-s<eps||a[i].y+s>y+eps)
			num[++tmp2][1]=i;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(fa[i]==fa[j])continue;
			double x_=a[i].x-a[j].x;
			double y_=a[i].y-a[j].y;
			if(sqrt(x_*x_+y_*y_)<2*s+eps)
			{
				if(find(i)!=find(j))
				fa[find(i)]=fa[find(j)];
			}
		}
	}
	for(int i=1;i<=tmp1;i++)
	{
		for(int j=1;j<=tmp2;j++)
		{
			if(find(num[i][0])==find(num[j][1]))
			return true;
		}
	}
	return false;
}

int main()
{
	x=read(),y=read(),n=read();
	for(int i=1;i<=n;i++)
	a[i].x=read(),a[i].y=read();
	double l=0,r=1e6,ans;
	while(r-l>=eps)
	{
		double mid=(l+r)/2.0;
		if(check(mid))
		{
			ans=mid;
			r=mid;
		}
		else l=mid;
	}
	printf("%.2f",ans);
	return 0;
}

摘果子

\(solution\)

连完边后在树上跑一个dfs序,然后01背包模板
注意要存子树大小,不选当前点i的下一个状态是:\(i+siz_i\)

AC Code
#include<bits/stdc++.h>
using namespace std;

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return x*f;
}

const int N=2e3+5;
const int inf=0x3f3f3f3f;
int n,m;
int v[N],p[N];
int vis[N],d[N],siz[N];
int tot,h[N],ver[N*2],nex[N*2];
int f[N][N],num;

void add(int x,int y)
{
	ver[++tot]=y,nex[tot]=h[x],h[x]=tot;
}

void dfs(int x)
{
	d[++num]=x;
	siz[x]=1;vis[x]=1;
	for(int i=h[x];i;i=nex[i])
	{
		int y=ver[i];
		if(vis[y])continue;
		dfs(y);
		siz[x]+=siz[y];
	}
}

int main()
{
//	freopen("fruit.in","r",stdin);
//	freopen("fruit.out","w",stdout);
	n=read(),m=read();
	for(int i=1;i<=n;i++)v[i]=read(),p[i]=read();
	int x,y;
	for(int i=1;i<n;i++)
	{
		x=read(),y=read();
		add(x,y);add(y,x);
	}
	dfs(1);
	for(int i=0;i<=n+1;i++)
	{
		for(int j=0;j<=m;j++)f[i][j]=-inf;
	}
	f[1][0]=0;
	for(int i=1;i<=n;i++)
	{
		x=d[i];
		for(int j=0;j<=m;j++)
		{
			if(j+p[x]<=m)
			{
				f[i+1][j+p[x]]=max(f[i+1][j+p[x]],f[i][j]+v[x]);
				f[i+siz[x]][j+p[x]]=max(f[i+siz[x]][j+p[x]],f[i][j]+v[x]);
			}
			f[i+siz[x]][j]=max(f[i+siz[x]][j],f[i][j]);
		}
	}
	int ans=0;
	for(int i=0;i<=m;i++)ans=max(ans,f[n+1][i]);
	printf("%d\n",ans);
	return 0;
}
posted @ 2022-08-22 18:26  两只风小鱼  阅读(22)  评论(0)    收藏  举报