The 2025 ICPC Asia East Continent Online Contest (II)

A

image

const int N=1e5+10;
const double pi=acos(-1);
struct node{
	int x,y;
	node(){x=y=0;}
	node(int xx,int yy){x=xx,y=yy;}
	bool operator==(const node&rhs)const{return x==rhs.x&&y==rhs.y;}
	double operator*(const node&rhs)const{return 1.0*x*rhs.y-1.0*y*rhs.x;}
	node operator+(const node&rhs)const{return node(x+rhs.x,y+rhs.y);}
	node operator-(const node&rhs)const{return node(x-rhs.x,y-rhs.y);}
	bool operator<(const node&rhs)const{return x!=rhs.x?x<rhs.x:y<rhs.y;}
}a[N],h[N];
double dis(node x,node y){return sqrt(1.0*(x.x-y.x)*(x.x-y.x)+1.0*(x.y-y.y)*(x.y-y.y));}
int st[N],top=0;
bool vis[N];
void sol()
{
	int n=read();double R2=read(),R3=read();
	for(int i=1;i<=n;i++)a[i].x=read(),a[i].y=read();
	for(int i=1;i<=n+1;i++)st[i]=0;
	for(int i=1;i<=n;i++)vis[i]=0;top=0;
	sort(a+1,a+n+1);n=unique(a+1,a+n+1)-a-1;
	st[++top]=1;
	for(int i=2;i<=n;i++)
	{
		while(top>=2&&(a[st[top]]-a[st[top-1]])*(a[i]-a[st[top]])<=0)vis[st[top--]]=0;
		vis[i]=1;
		st[++top]=i;
	}
	int tmp=top;
	for(int i=n-1;i;i--)if(!vis[i])
	{
		while(top>tmp&&(a[st[top]]-a[st[top-1]])*(a[i]-a[st[top]])<=0)vis[st[top--]]=0;
		vis[i]=1;
		st[++top]=i;
	}
	for(int i=1;i<=top;i++)h[i]=a[st[i]];
	int cnt=top-1;
	double A=0,C=0;
	for(int i=1;i<=cnt;i++)C+=dis(h[i],h[i+1]);
	for(int i=1;i<=cnt;i++)A+=h[i]*h[i+1]/2;
	double Ans=2.0*A*R3+2.0*C*R2*R3+2*pi*R3*(1.0*R2*R2+1.0*R3*R3)+0.5*pi*R3*R3*(C+2*pi*R2)-2.0/3.0*pi*R3*R3*R3;
	printf("%.9Lf\n",Ans);
}
int main()
{
	int T=read();
	while(T--)sol();
	return 0; 
}

B

考虑层分别做

这是一个匹配问题,可以行列连边,然后上下界费用流

不会写咋办?正难则反,考虑保留最多的,限制从 \(S\)\(i\) 至少流 \(1\) 变成 \(S\)\(i\) 至多流 \(c-1\)\(c\) 表示这一行有几列是能用的,列同理,最大费用流即可。

namespace MCMF
{
	const int N=5e3+10,M=1e5+10,inf=0x3f3f3f3f3f3f3f3f;
	int head[N],ver[M],nxt[M],tot=1,edge[M],cost[M];
	bool vis[N];
	void init(){memset(head,0,sizeof(head));tot=1;}
	void add0(int x,int y,int z,int c)
	{
		ver[++tot]=y,edge[tot]=z,cost[tot]=c;
		nxt[tot]=head[x],head[x]=tot;
	}
	void add(int x,int y,int z,int c)
	{
//		printf("add(%lld, %lld, %lld, %lld)\n",x,y,z,c);
		add0(x,y,z,c),add0(y,x,0,-c);
	}
	int dis[N],cur[N];
	bool spfa(int s,int t)
	{
		memset(dis,-0x3f,sizeof(dis));
		memcpy(cur,head,sizeof(head));
		queue<int> que;que.push(s),dis[s]=0;
		while(!que.empty())
		{
			int x=que.front();que.pop();
			vis[x]=0;
			for(int i=head[x];i;i=nxt[i])
			{
				int y=ver[i],z=edge[i],c=cost[i];
				if(z&&dis[x]+c>dis[y])
				{
					dis[y]=dis[x]+c;
					if(!vis[y])vis[y]=1,que.push(y);
				}
			}
		}
		return dis[t]>=0;
	}

	int res=0;
	int dfs(int x,int t,int limit)
	{
		if(x==t||!limit)return limit;
		int flow=0,rlow=0;vis[x]=1;
		for(int &i=cur[x];i;i=nxt[i])
		{
			int y=ver[i],z=edge[i],c=cost[i];
			if(z&&!vis[y]&&dis[x]+c==dis[y])
			{
				rlow=dfs(y,t,min(limit,z));
				if(rlow)flow+=rlow,limit-=rlow,edge[i]-=rlow,edge[i^1]+=rlow,res+=rlow*c;
				if(!limit)break;
			}
		}
		vis[x]=0;
		return flow;
	}
	pii dinic(int s,int t)
	{
		int ans=0;res=0;
		while(spfa(s,t))
		{
			int x=0;
			while(x=dfs(s,t,inf))ans+=x;
		}
		// ans:maxflow  res:mincost
		return mp(ans,res);
	}
}
using namespace MCMF;
const int NN=1010;
int val[NN],L,W,H;
char a[NN][NN],b[NN][NN],c[NN][NN];
int id(int i,int j,int k){return ((i-1)*W+j-1)*H+k;}
struct node{
	int x,y,z;
	node(){x=y=z=0;}
	node(int xx,int yy,int zz){x=xx,y=yy,z=zz;}
};
void sol()
{
	L=read(),W=read(),H=read();
	for(int i=1;i<=L*W*H;i++)val[i]=read();
	for(int i=1;i<=H;i++)scanf("%s",a[i]+1);
	for(int i=1;i<=H;i++)scanf("%s",b[i]+1);
	for(int i=1;i<=W;i++)scanf("%s",c[i]+1);
	bool flag=1;
	ll ans=0;
	vector<node>Ans;
	for(int k=1;k<=H;k++)
	{
		init();
		tot=1;
		memset(head,0,sizeof(head));
		int s=0,t=L+W+1;
		for(int i=1;i<=L;i++)
		{
			if(!(a[k][i]^48))continue;
			int cnt=0;
			for(int j=1;j<=W;j++)
			{
				if(!(b[k][j]^48))continue;
				cnt+=c[j][i]^48;
			}
			if(!cnt){flag=0;break;}
			add(s,i,cnt-1,0);
		}
		if(!flag)break;
		for(int j=1;j<=W;j++)
		{
			if(!(b[k][j]^48))continue;
			int cnt=0;
			for(int i=1;i<=L;i++)
			{
				if(!(a[k][i]^48))continue;
				cnt+=c[j][i]^48;
			}
			if(!cnt){flag=0;break;}
			add(j+L,t,cnt-1,0);
		}
		if(!flag)break;
		int sum=0;
		for(int i=1;i<=L;i++)for(int j=1;j<=W;j++)if((a[k][i]^48)&&(b[k][j]^48)&&(c[j][i]^48))
		{
			sum+=val[id(i,j,k)];
			add(i,j+L,1,val[id(i,j,k)]);
		}
		pii tmp=dinic(s,t);
		for(int x=1;x<=L;x++)
		{
			for(int i=head[x];i;i=nxt[i])
			{
				int y=ver[i],z=edge[i];
				if(!y)continue;
				if(z)Ans.pb(node(x,y-L,k));
			}
		}
		ans+=sum-tmp.se;
	}
	if(!flag){puts("NO");return;}
	puts("YES");
	printf("%lld\n%lld\n",ans,(int)Ans.size());
	for(node it:Ans)printf("%lld %lld %lld\n",it.x,it.y,it.z);
}
signed main()
{
	int T=read();
	while(T--)sol();
	return 0;
}

C

队友写的,回头补

D

肯定是从大到小选,分开考虑每个点的贡献,最后二项式定理能推出来一个式子,\(\mathcal O(n)\) 即可。

E

队友写的,回头补

H

考虑长度为 \(l\) 的链,容斥可以求出有多少种排列方式使得选择的 最短的操作序列\(l\)

然后 \(\mathcal O(n^2)\) 求出树上有多少个长度为 \(i\) 的链即可。

J

队友写的,回头补

K

外子树 dp

考虑 \(f(i,j)\) 表示 \(i\) 子树内,包含 \(i\),大小为 \(j\) 的连通块数量,\(g(i,j)\) 表示子树外,\(f\) 树形背包求出,\(g\) 可通过 \(f\) 转移。

精细处理上界(\(sz_i\))可将 \(g\)\(f\) 做到一个复杂度。

const int N=3010,M=N<<1,mod=998244353;
void Add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
void Sub(int &x,int y){x-=y;if(x<0)x+=mod;}
int head[N],ver[M],nxt[M],tot=0;
void add(int x,int y)
{
    ver[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}
vi mul(vi a,vi b)
{
    vi ans(a.size()+b.size()-1,0);
    for(int i=0;i<(int)a.size();i++)for(int j=0;j<(int)b.size();j++)Add(ans[i+j],1ll*a[i]*b[j]%mod);
    return ans;
}
int sz[N],Ans;vi f[N],g[N],pre[N],suf[N];
void dfs(int x,int fa)
{
    sz[x]=1;
    f[x]=vi{0,1};
    vi son;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=ver[i];if(y==fa)continue;
        son.pb(y);
        dfs(y,x);
        sz[x]+=sz[y];
        f[y][0]=1,f[x]=mul(f[x],f[y]),f[y][0]=0;
    }
}
void dfs1(int x,int fa)
{
    int cnt=0;vi son;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=ver[i];if(y==fa)continue;
        son.pb(y),cnt++;
    }
    for(int i=0;i<cnt;i++)
    {
        int y=son[i];
        f[y][0]=1;
        if(i==0)pre[i]=f[y];
        else pre[i]=mul(pre[i-1],f[y]);
        f[y][0]=0;
    }
    for(int i=cnt-1;~i;i--)
    {
        int y=son[i];
        f[y][0]=1;
        if(i==cnt-1)suf[i]=f[y];
        else suf[i]=mul(suf[i+1],f[y]);
        f[y][0]=0;
    }
    if(!fa)g[x]=vi(1);
    g[x][0]=1;
    for(int i=0;i<cnt;i++)
    {
        int y=son[i];
        g[y]=mul(g[x],vi{0,1});
        g[y].resize(sz[y]+1);
        if(i)g[y]=mul(g[y],pre[i-1]),g[y].resize(sz[y]+1);
        if(i<cnt-1)g[y]=mul(g[y],suf[i+1]),g[y].resize(sz[y]+1);
    }
    g[x][0]=0;
    for(int y:son)dfs1(y,x);
}
void dfs2(int x,int fa)
{
    for(int i=1;i<(int)f[x].size();i++)Add(Ans,f[x][i]);
    for(int i=head[x];i;i=nxt[i])
    {
        int y=ver[i];if(y==fa)continue;
        dfs2(y,x);
        for(int j=1;j<(int)min(g[y].size(),f[y].size());j++)Sub(Ans,1ll*g[y][j]*f[y][j]%mod);
    }
}
void sol()
{
    int n=read();
    tot=0;for(int i=1;i<=n;i++)head[i]=0;
    for(int i=1;i<n;i++)
    {
        int u=read(),v=read();
        add(u,v),add(v,u);
    }
    for(int i=1;i<=n;i++)vi().swap(f[i]),vi().swap(g[i]),vi().swap(pre[i]),vi().swap(suf[i]);
    Ans=0;dfs(1,0),dfs1(1,0),dfs2(1,0);
    printf("%d\n",Ans);
}
int main()
{
    // freopen("1.in","r",stdin);
    int T=read();
    while(T--)sol();
    return 0;
}
posted @ 2025-09-18 21:45  zzt1208  阅读(15)  评论(0)    收藏  举报