Codeforces Gym 103428

是CCPC2021威海站的题

只有E H J M

其实是模拟赛

T1(J)

签到,手摸发现一定是每条边长度相等。

然后你考虑到角度大小相等。

乱求一下 \(\gcd\) 即可。

查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t,a,b;
signed main(){
	ios::sync_with_stdio(0);
	cin>>t;
	while(t--){
		cin>>a>>b;
		b*=180;
		int tt=__gcd(a,b);
		b/=tt;
		cout<<b-1<<'\n';
	}
	return 0;
} 

T2(M)

数学题

熔池容斥好题!

先抽象出一个问题:(注意下面的 \(n,m,k\) 不同于原题的 \(n,m,k\)

\(0\text{到}n\) 中选择 \(m\) 个数使得它们的和为 \(k\)

假设没有 \(n\) 的限制,就是经典隔板法了。

\(C^{m-1}_{k+m-1}\)

然后你再把 \(n\) 的限制考虑进去。

那么 \(n\) 时的答案是:

\(f_i=C^{m-1}_{k+m-1-i\times n}\times C^i_m\)

这个东西因为可能会算重复,奇加偶减容斥即可

最后再容斥一遍,\(n\) 的答案减掉 \(n+1\) 的答案就可以了。

怎么把两个 \(n,m,k\) 对应呢,读者自证不难(doge

查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
int qpow(int a,int b){
	int ans=1,base=a;
	while(b){
		if(b&1)ans=ans*base%mod;
		base=base*base%mod;
		b>>=1;
	}
	return ans;
}
int inv(int x){
	return qpow(x,mod-2);
}
int n,m,k;
//真正的顺序为:k,n-m+1,m 
int jc[200005];
int C(int x,int y){
	if(x>y)return 0;
	return jc[y]*inv(jc[y-x])%mod*inv(jc[x])%mod;
}
int calc(int x){
	int ans=0;
	for(int i=1;i*x<=k;++i){
		if(i&1)ans=(ans+C(m-1,k+m-1-i*x)*C(i,m)%mod)%mod;
		else ans=(ans-C(m-1,k+m-1-i*x)*C(i,m)%mod+mod)%mod;
	}
//	for(int i=0;i<=min(m,k/m);++i)dp[i]=;
	return ans;
}
signed main(){
	int a,b,c;
	ios::sync_with_stdio(0);
	cin>>a>>b>>c;
	n=c,m=a-b+1,k=b;
	if(n==0){
		cout<<(k==0);
		return 0;
	}
	jc[0]=1;
	for(int i=1;i<=k+m;++i)jc[i]=jc[i-1]*i%mod;
	cout<<((calc(n)-calc(n+1))%mod+mod)%mod;
	return 0;
}

T3(E)

神仙期望

我们设 \(dp_i\) 表示你再选 \(i\) 次的期望得分(虽然实现的时候代码统一下标加了 \(1\) 的说)

先玩一下 \(dp_0\),自然就是所有情况除以方案数了!

\(dp_0=2\frac{\sum_{1\le i<j\le n}{}(a_i+a_j)}{n\times (n-1)}\)

查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const double eps=1e-6;
int n,k,Q,a[100005],b[100005];
long long sum[100005];
double dp[100005];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>k>>Q;
	for(int i=1;i<=n;++i)cin>>a[i],b[i]=a[i];
	sort(a+1,a+n+1);
	for(int i=1;i<=n;++i)sum[i]=sum[i-1]+a[i];
	for(int i=1;i<=k+1;++i){
		int lt=1,rt=n;
		double summ=0;
		while(lt<=n){
			while(lt<rt&&a[lt]+a[rt]>=dp[i-1])rt--;
			rt=max(lt,rt);
			summ+=(rt-lt)*dp[i-1]+(n-rt)*a[lt]+sum[n]-sum[rt];
			lt++;
		}
//		cout<<summ<<'\n';
		dp[i]=summ/((n-1)*n/2);
	}
	cout<<fixed<<setprecision(10)<<dp[k+1]<<'\n';
	while(Q--){
        int x,y,c;
		cin>>x>>y>>c;
        double summ=b[x]+b[y];
//        cout<<summ<<" "<<dp[c]<<endl; 
        if(c==0){
            cout<<"accept\n";
            continue;
        }
        if(abs(summ-dp[c])<eps){
            cout<<"both\n";
        }
        else if(summ+eps>dp[c]){
            cout<<"accept\n";
        }
        else{
            cout<<"reselect\n";
        }
    }
    return 0;
}

之后的每次就是把所有小于上一次的期望的 \(a_i+a_j\) 全部替换成上一次的期望即可。

T4(H)

网络流最小割问题,需要卡常避坑优化写法等一系列操作。

建模:\(v_{i,p}\) 表示把距离点 \(i\) 不超过 \(p\) 的点全部选掉。

\(u_i\) 表示每个点。

源点向每个 \(v_{i,p}\) 建边,为 \(v_p-v_{p-1}\),保证一级一级降。

\(v_{i,p}\) 往距离 \(i\)\(p\) 的点建边。

每个\(v_{i,p}\)\(v_{i,p-1}\)连边 inf,表示必须先割 \(v_{i,p}\) 才能割 \(v_{i,p-1}\)

然后 \(u_i\) 往汇点连 \(w_i\) 即可。

跑最小割即为答案。

查看代码
// Codeforces Gym 103428 (CCPC Weihai Onsite) M 
#include<bits/stdc++.h>
//#define int long long
#define inf (int)1e9
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
using namespace std;
int n,m,s,t,head[10000005],nxt[10000005],edge[10000005],to[10000005],pre[10000005],level[10000005];
int tot;
void add(int u,int v,int w){
    to[++tot]=v;
    edge[tot]=w;
    nxt[tot]=head[u];
    head[u]=tot;
    to[++tot]=u;
    edge[tot]=0;
    nxt[tot]=head[v];
    head[v]=tot;
}
bool bfs(){
    memset(level,0,sizeof(level));
    queue<int>q;
    level[s]=1;
    q.push(s);
    while(!q.empty()){
        int cur=q.front();
        q.pop();
        for(int i=head[cur];i;i=nxt[i]){
            if(edge[i]&&!level[to[i]]){
                q.push(to[i]);
                level[to[i]]=level[cur]+1;
                if(to[i]==t)return 1;
            }
        }
    }
    return 0;
}
int Dinic(int x,int flow){
    if(x==t)return flow;
    int rest=flow,increase;
    for(int i=head[x];i&&rest;i=nxt[i]){
        int y=to[i];
        if(edge[i]&&level[y]==level[x]+1){
            increase=Dinic(y,min(rest,edge[i]));
            if(!increase)level[y]=0;
            edge[i]-=increase;
            edge[i^1]+=increase;
            rest-=increase;
        }
    }
    return flow-rest;
}
vector<int>nbr[205];
int d[205],dp[205][12];
void _add(int u,int v){
	nbr[u].push_back(v);
	return;
}
void before(int cur,int fa){
	d[cur]=d[fa]+1;
	dp[cur][0]=fa;
	for(int i=1;i<=10;++i)dp[cur][i]=dp[dp[cur][i-1]][i-1];
	for(auto to:nbr[cur]){
		if(to==fa)continue;
		before(to,cur);
	}
	return;
}
int LCA(int u,int v){
	if(d[u]<d[v])swap(u,v);
	for(int i=10;i>=0;i--){
		if(d[u]-d[v]>=(1<<i))u=dp[u][i];
	}
	if(u==v)return u;
	for(int i=10;i>=0;i--){
		if(dp[u][i]!=dp[v][i]){
			u=dp[u][i];
			v=dp[v][i];
		}
	}
	return dp[u][0];
}
int calc(int u,int v){
	int lca=LCA(u,v);
	return d[u]+d[v]-d[lca]*2;
}
//V_{i,p}->(i-1)*n+p+1;  u_i->(n-1)*n+i
int U(int i){
	return n*n+i;
}
int V(int i,int p){
	return (i-1)*n+p;
}
int w[205],v[205],dis[205][205];
vector<int>_[205][205];
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    tot=1;
    int res=0;
    for(int i=1;i<=n;++i)cin>>w[i];
    for(int i=1;i<=n;++i)cin>>v[i];
    for(int i=1;i<n;++i){
        int u,v;
        cin>>u>>v;
        _add(u,v);
        _add(v,u); 
    }
    before(1,0);
	s=0,t=n*(n+1)+1;
//	for(int i=1;i<=n;++i){
//		cout<<"Point "<<i<<": \n";
//		cout<<d[i]<<'\n';
//		for(int j=0;j<=10;++j)cout<<dp[i][j]<<' ';
//		cout<<'\n';
//	}
    int flow=0,maxflow=0,sum=n*v[n];
    for(int i=1;i<=n;++i)add(U(i),t,w[i]);
    for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)dis[i][j]=calc(i,j),_[i][dis[i][j]].push_back(j);
    for(int i=1;i<=n;++i){
    	for(int p=1;p<=n;++p){
    		add(s,V(i,p),v[p]-v[p-1]);
    		if(p>1)add(V(i,p),V(i,p-1),inf);
    		for(auto j:_[i][p-1]){
//    			if(dis[i][j]!=p)continue;
    			add(V(i,p),U(j),inf);
			}
		}
	}
    while(bfs())maxflow+=Dinic(s,inf);
    cout<<sum-maxflow;
    return 0;
}
posted @ 2023-01-10 09:00  Forever1507  阅读(23)  评论(0编辑  收藏  举报