返回顶部

csp-s模拟12

题面

首先,这些题目的题意就不太好理解

A

利用三个中点,暴力就是暴力算斜率暴力算交点
圆周率别再写错了const double Pi=acos(-1);

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 5e5+5,INF=1E9;
const double eps=1e-9,P=1e9,pai=3.14159265358;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
struct dawn
{
	double  x,y,jiao;
	bool operator < (const dawn &A)const
	{
		return x<A.x;
	}
}a[N];
int n;
#define pdd pair<double,double>
pdd calckxb(int i,int j)
{
	double k=(a[i].y-a[j].y)/(a[i].x-a[j].x);
	double b=a[i].y-k*a[i].x;
	// printf("%.10lf %.10lf\n",k,b);
	return {k,b};
}
pdd calckxb(pdd i,pdd j)
{
	double k=(i.second-j.second)/(i.first-j.first);
	double b=i.second-k*i.first;
	// printf("%.10lf %.10lf\n",k,b);
	return {k,b};
}
pdd calcjiao(pdd i,pdd j)
{
	double x=(j.second-i.second)/(i.first-j.first);
	double y=i.first*x+i.second;
	return {x,y};
}
pdd calczcx(pdd i,pdd xy)
{
	// cout<<i.first<<" "<<i.second<<endl;
	double k=-1.0/i.first;
	double b=xy.second-k*xy.first;
	// printf("%.10lf %.10lf\n",k,b);
	return {k,b};
}
pdd calcmid(int i,int j)
{
	// printf("%.10lf %.10lf\n",(a[i].x+a[j].x)/2.0,(a[i].y+a[j].y)/2.0);
	return {(a[i].x+a[j].x)/2.0,(a[i].y+a[j].y)/2.0};
}
pdd calcmid(pdd i,pdd j)
{
	// printf("%.10lf %.10lf\n",(a[i].x+a[j].x)/2.0,(a[i].y+a[j].y)/2.0);
	return {(i.first+j.first)/2.0,(i.second+j.second)/2.0};
}
double dis(pdd i,pdd j)
{
	return (i.first-j.first)*(i.first-j.first)+(i.second-j.second)*(i.second-j.second);
}
pdd calcyuanxin(int i,int j,int k)
{
	pdd x1=calcmid(i,j),x2=calcmid(i,k),x3=calcmid(j,k);
	pdd t1=calckxb(x1,x2),t2=calckxb(x2,x3);
	pdd k1=calczcx(t1,calcmid(x1,x2)),k2=calczcx(t2,calcmid(x2,x3));
	pdd xy1=calcjiao(k1,k2);
	// printf("%.10lf\n",dis(xy1,x2));
	return xy1;
}

int main(int argc, char const *argv[])
{
	// file("a");
	freopen("geometry.in","r",stdin);freopen("geometry.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++)
	{
		a[i].jiao=read()/P*pai;
		a[i].x=cos(a[i].jiao);
		a[i].y=sin(a[i].jiao);
		// cout<<a[i].x<<" "<<a[i].y<<endl;
	}
	double ansx=0,ansy=0;
	if(n>1000)
	{
		printf("%.15lf %.15lf",ansx,ansy);
		return 0;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			for(int k=j+1;k<=n;k++)
			{
				// cout<<i<<" "<<j<<" "<<k<<endl;
				pdd tmp=calcyuanxin(i,j,k);
				ansx+=tmp.first;ansy+=tmp.second;
			}
		}
	}
	ansx*=6.0/(n*(n-1)*(n-2));
	ansy*=6.0/(n*(n-1)*(n-2));
	printf("%.15lf %.15lf",ansx,ansy);
	return 0;
}

九点圆具体细节及扩展
设△ABC的垂心为\(H\)外心,为\(O\)

$ \overrightarrow {OH}=\overrightarrow{OA}+\overrightarrow{OB}+\overrightarrow{OC}$

证明:

\(\overrightarrow{OB}+\overrightarrow{OC}=\overrightarrow{OG}\)
\(OG\)垂直\(BC\),与过点\(A\)的高平行,则$ \overrightarrow {OH}=\overrightarrow{OA}+\overrightarrow{OB}+\overrightarrow{OC}$ 一定落在过点\(A\)的高上
同理一定落在\(B,C\)的高上,位置相同所以等价于三条高的交点垂心\(H\)
九点圆圆心是外心\(O\)和垂心\(H\)的中点,\(O(0,0)\)则答案即为\(\large ans_x=\sum{\frac{x_i+x_j+x_k}{2}},ans_y=\sum{\frac{y_i+y_j+y_k}{2}}\)
发现这玩意能直接求,每个出现的概率为\(P_i=\frac{C(n-1,2)}{C(n,3)}=\frac{n}{3}\)则答案为\(ans_x=\sum P_i\times \frac{x_i}{2}\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 5e5+5,INF=1E9;
const double eps=1e-9,P=1e9,pai=3.14159265358;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
struct dawn
{
	double  x,y,jiao;
	bool operator < (const dawn &A)const
	{
		return x<A.x;
	}
}a[N];
int n;
#define pdd pair<double,double>

int main(int argc, char const *argv[])
{
	// file("a");
	freopen("geometry.in","r",stdin);freopen("geometry.out","w",stdout);
	n=read();
	double ansx=0,ansy=0;
	for(int i=1;i<=n;i++)
	{
		a[i].jiao=read()/P*pai;
		a[i].x=cos(a[i].jiao);
		a[i].y=sin(a[i].jiao);
		ansx+=a[i].x/2.0;
		ansy+=a[i].y/2.0;
		// cout<<a[i].x<<" "<<a[i].y<<endl;
	}
	ansx*=3.0/n;
	ansy*=3.0/n;
	printf("%.15lf %.15lf",ansx,ansy);
	return 0;
}

B

部分分,菊花图和链的情况直接一个式子,是树的情况的话相当于树上统计上升子序列的方案数可以\(O(n^3)\)优化成\(O(n^2log n)\),基环树的话需要略微容斥一下

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 500+5,INF=1E9,mod=998244353;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
#define bs bitset<10>
int n,m,ans;
std::vector<int> edge[N];
std::vector<int> v;bool vis[N];
int stk[N],top;
inline bool dfs(int u,int len)
{
	// if(mp[zt])return;
	// cout<<u<<endl;
	// ts;
	if(len==top)
	{
		return 1;
	}
	// v.pb(u);
	bool f=0;
	for(auto to:edge[u])
	{
		if(vis[to])continue;
		vis[to]=1;
		f|=dfs(to,len+(to==stk[len+1]));
		vis[to]=0;
		if(f)return 1;
	}
	// v.pop_back();
	return f;
}
inline ll qpow(ll a,ll b)
{
	ll ans=1;
	while(b)
	{
		if(b&1)ans=ans*a%mod;
		a=a*a%mod;b>>=1;
	}
	return ans;
}
inline int lowbit(int x)
{
	return x&-x;
}
ll c[N];
inline ll query(int x)
{
	ll ans=0;
	while(x){ans+=c[x];ans%=mod;x-=lowbit(x);}
	return ans;
}
inline void add(int x,int v)
{
	while(x<=n)
	{
		c[x]+=v;c[x]%=mod;
		x+=lowbit(x);
	}
}
ll f[N];
inline void dp(int u,int F,int rt)
{
	if(u==rt)f[u]=1;
	if(u>=rt)add(u,f[u]);
	for(auto to:edge[u])
	{
		if(to==F)continue;
		
		if(to>=rt)
		{
			f[to]=(query(to-1)+mod)%mod;
			ans=(ans+f[to])%mod;
			
		}
		dp(to,u,rt);
	}
	if(u>=rt)add(u,-f[u]);
	// cout<<u<<" "<<f[u][0]<<" "<<f[u][1]<<" "<<f[u][2]<<endl;
}
int main(int argc, char const *argv[])
{
	file("a");
	// freopen("algebra.in","r",stdin);freopen("algebra.out","w",stdout);
	n=read();m=read();
	bool lian=1;bool flower=1;
	for(int i=1,u,v;i<=m;i++)
	{
		u=read();v=read();
		edge[u].pb(v);edge[v].pb(u);
		if(abs(u-v)!=1)lian=0;
		if(min(u,v)!=1)flower=0;
	}
	if(lian)
	{
		write((qpow(2,n)-1+mod)%mod);
		putchar_unlocked('\n');
		return 0;
	}else if(flower)
	{
		ans=n*(n-1)%mod*qpow(2,mod-2)%mod;
		ans=(ans+n)%mod;
		write(ans);
		putchar_unlocked('\n');
		return 0;
	}else if(n-1==m)
	{
		for(int i=1;i<=n;i++)
		{
			// ts;
			// cout<<i<<endl;
			memset(c,0,sizeof c);
			dp(i,0,i);
		}
		write(ans+n);
		putchar_unlocked('\n');
		return 0;
	}

	ans=0;
	for(int i=1;i<(1<<n);i++)
	{
		int st=0;top=0;
		for(int j=0;j<n;j++)
		{
			if(i>>j&1)stk[++top]=j+1;
		}
		// for(int j=1;j<=top;j++)cout<<stk[j]<<" ";cout<<endl;
		st=stk[1];
		vis[st]=1;
		if(dfs(st,1))
		{
			// cout<<bs(i)<<endl;
			ans++;
			if(ans>mod)ans-=mod;
		}
		vis[st]=0;
	}

	write(ans);
	return 0;
}

正解,因为是仙人掌,考虑先用圆方树建虚点,虚点所连的点\((cnt>=2)\)就是一个环,正常的一维\(dp\)无法满足需求,所以可以开二维记录到链尾,\(dp_{u,i}\)表示到\(u\)结点,链尾元素是\(i\)的方案数,最初一定为\(dp_{u,u}=1\),考虑如何转移,如果是树的部分,我们只需要正常转移\(dp_{u,u}\leftarrow dp_{u,i},i<u\),考虑环的情况,可以正着做一遍反着做一遍,但是,考虑一种情况就是不在环上任意一个点停的情况会被统计两次,最后只需删掉一次即可,注意转移的时候环上的点不能直接更新,会重复计算,所以要开一个\(tmp\)数组

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 1000+5,INF=1E9,mod=998244353;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
#define bs bitset<10>
int n,m;
std::vector<int> edge[N];
int dfn[N],low[N],dfstot,bl[N];
bool vis[N];stack <int> stk;
std::vector<int> Graph[N];
int cnt;
inline void tarjan(int u,int F)
{	
	low[u]=dfn[u]=++dfstot;
	stk.push(u);
	// cout<<u<<endl;
	for(auto to:edge[u])
	{
		// if(to==F)continue;
		if(!dfn[to])
		{
			tarjan(to,u);
			low[u]=min(low[u],low[to]);
			if(low[to]>=dfn[u])
			{
				// cout<<"**"<<u<<endl;
				cnt++;int x;
				do
				{
					x=stk.top();stk.pop();
					Graph[cnt].pb(x);
					Graph[x].pb(cnt);
					// cout<<x<<" "<<cnt<<endl;
				}while(x!=to);
				Graph[cnt].pb(u);
				// cout<<u<<" "<<cnt<<endl;
				Graph[u].pb(cnt);
			}
		}else 
		{
			low[u]=min(low[u],dfn[to]);
		}
	}
}	
ll dp[N][N],ans,tmp[N];
inline void add(ll &u,ll v)
{
	u=u+v;
	if(u>mod)u-=mod;
}
inline void dfs(int u,int F)
{
	if(u<=n)
	{
		for(int i=1;i<u;i++)
		{
			add(dp[u][u],dp[u][i]);
		}
		for(auto to:Graph[u])
		{
			if(to==F)continue;
			dfs(to,u);
		}		
	}else
	{
		std::vector<int> s;
		int idx=0;
		for(int i=0;i<Graph[u].size();i++)
			if(Graph[u][i]==F)
				{idx=i;break;}
		for(int i=(idx+1)%Graph[u].size();i!=idx;i=(i+1)%Graph[u].size())s.pb(Graph[u][i]);
		memcpy(tmp,dp[F],sizeof tmp);
		for(auto to:s)
		{
			for(int i=1;i<=n;i++)add(dp[to][i],tmp[i]);
			for(int i=1;i<to;i++)add(tmp[to],tmp[i]);
		}
		memcpy(tmp,dp[F],sizeof tmp);
		reverse(s.begin(), s.end());
		for(auto to:s)
		{
			for(int i=1;i<=n;i++)add(dp[to][i],tmp[i]);
			for(int i=1;i<to;i++)add(tmp[to],tmp[i]);
		}
		for(auto to:s)
		{
			for(int i=1;i<=n;i++)
				add(dp[to][i],mod-dp[F][i]);
		}	
		for(auto to:Graph[u])
		{
			if(to==F)continue;
			dfs(to,u);
		}
	}


}

int main(int argc, char const *argv[])
{
	// file("a");
	freopen("algebra.in","r",stdin);freopen("algebra.out","w",stdout);
	n=read();m=read();
	cnt=n;
	for(int i=1,u,v;i<=m;i++)
	{
		u=read();v=read();
		edge[u].pb(v);edge[v].pb(u);
	}
	tarjan(1,0);
	// for(int i=1;i<=n;i++)cout<<low[i]<<" "<<dfn[i]<<endl;
	for(int i=1;i<=n;i++)
	{
		memset(dp,0,sizeof dp);
		dp[i][i]=1;
		dfs(i,0);
		for(int j=1;j<=n;j++)
		{
			if(j>=i)
				add(ans,dp[j][j]);
		}
	}
	write(ans);
	return 0;
}

C

D

随机化挺难拿到分
观察性质:发现新加入一个点\(v'\),相当于可以多经过一次\(v\),在一个树上度数\(>2\)的一定要加新点,考虑什么情况下加的点最少,显然是走遍历到的当前一个子树的直径的时候所需新加的点最少,点数为\(经过的点数-直径\),所以每次优先遍历非直径的点,判断直径是否为全局直径,是否为子树内的,若是子树内的则还需额外一次

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define pb push_back
#define ull unsigned long long
#define pii pair<int,int>
#define lid (rt<<1)
#define rid (rt<<1|1)
#define file(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
#define ts cout<<"************"<<endl;
using namespace std;
const int N = 1e4+5,INF=1E9;
inline int read()
{
	int x=0,f=1;char ch=getchar_unlocked();
	for(;ch<'0'||ch>'9';ch=getchar_unlocked())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar_unlocked())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;	
}
inline void write(ll x)
{
	if(x<0)x=-x,putchar_unlocked('-');
	if(x>9)write(x/10);
	putchar_unlocked((x%10)|48);
}
inline void write(ll x,char p)
{
	write(x);putchar_unlocked(p);
}
int n,ans,pos[N];
std::vector<int> edge[N];
int mx[N],dep[N],son[N],rt;
inline void dfs(int u,int F)
{
	mx[u]=dep[u]=dep[F]+1;
	son[u]=0;
	for(auto to:edge[u])
	{
		if(to==F)continue;
		dfs(to,u);
		son[u]=(mx[to]>mx[son[u]])?to:son[u];
		mx[u]=max(mx[u],mx[to]);
	}
}
std::vector<int> put;
bool vis[N];
int tot;
inline void dfs2(int u,int F,int n)
{
	tot++;
	put.pb(u);
	if(son[u])
	{
		for(auto to:edge[u])
		{
			if(to==F||to==son[u])continue;
			dfs2(to,u,n);
			put.pb(u);
		}	
		dfs2(son[u],u,n);
		if(tot!=n)	
		{
			put.pb(u);
		}
	}

}
int idx;
int main(int argc, char const *argv[])
{
	// file("a");
	freopen("combo.in","r",stdin);freopen("combo.out","w",stdout);
	n=read();
	for(int i=1,u,v;i<=n-1;i++)
	{
		u=read();v=read();
		edge[u].pb(v);edge[v].pb(u);
	}
	dfs(1,0);
	idx=n;
	for(int i=1;i<=n;i++)
		if(dep[i]>dep[rt])rt=i;
	// cout<<rt<<endl;
	dfs(rt,0);
	// for (int i = 1; i <= n; i++)cout<<son[i]<<" ";cout<<endl;
	dfs2(rt,0,n);
	write(put.size()-n,'\n');
	for(auto &i:put)
	{
		if(!vis[i])vis[i]=1;
		else write(i,' '),i=++idx;
	}
	putchar_unlocked('\n');
	for(auto i:put)
	{
		write(i,' ');
	}	
	return 0;
}
posted @ 2024-10-18 21:24  wlesq  阅读(20)  评论(0编辑  收藏  举报