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;
}