2023ICPC网络赛简单题解

不知道在干什么,哈哈

A.Qualifiers Ranking Rules

题意:给定两场比赛的排名,进行去重,归并排序然后输出最后的rank
思路:实现输出即可

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=0;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
int n,m;
std::vector<string> r1,r2,r3;
set<string>st;
string s;
void solve(){
	cin>>n>>m;
	st.clear();
	for(int i=1;i<=n;i++){
		cin>>s;
		if(!st.count(s)){
			st.insert(s);
			r1.push_back(s);
		}
	}
	st.clear();
	for(int i=1;i<=m;i++){
		cin>>s;
		if(!st.count(s)){
			st.insert(s);
			r2.push_back(s);
		}
	}
	st.clear();
	for(int i=0;i<max(r1.size(),r2.size());i++){
		if(i<r1.size()&&!st.count(r1[i])){
			st.insert(r1[i]);
			r3.push_back(r1[i]);
		}
		if(i<r2.size()&&!st.count(r2[i])){
			st.insert(r2[i]);
			r3.push_back(r2[i]);
		}
	}
	for(auto v:r3){
		cout<<v<<endl;
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	// cin>>t;
	while(t--){
		solve();
	}
}

L.KaChang!

题意:给定标程的运行时间和n个应该通过的程序的运行时间,问至少要开几倍的时间才能使所有程序通过(至少为2)
思路:排序,然后 m a x ( ( a [ i ] + t − 1 ) / t , 2 ) max((a[i]+t-1)/t,2) max((a[i]+t1)/t,2)即可

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=1e5+5;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
int n,t,a[N];
void solve(){
	cin>>n>>t;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+1+n);
	int ans=(a[n]+t-1)/t;
	cout<<max(ans,2)<<endl;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	// cin>>t;
	while(t--){
		solve();
	}
}

D.Transitivity

题意:给定一个不连通的图,如果一个子图连通那么其就是完全图,至少添加一条边,问最少添加几条边才能满足要求
思路:求出所有连通块,全部变成完全图,如果已经有了加边的操作,则已经满足要求。否则把两个拥有节点个数最少的联通块变成一个,然后再加边使其变成完全图。

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=1e6+5;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
struct graph{
	int cnte,hd[N];
	struct  edge{
		int v,nt;
	}e[N<<1];
	void addedge(int v,int u){
		e[++cnte].v=u;
		e[cnte].nt=hd[v];
		hd[v]=cnte;
	}
};
graph g;
int n,m,vis[N];
int cnt=0;
pair<ll,ll>bk[N];
void dfs(int x){
	vis[x]=1;
	// cout<<cnt<<" "<<x<<endl;
	bk[cnt].fi++;
	for(int i=g.hd[x];i;i=g.e[i].nt){
		int v=g.e[i].v;
		bk[cnt].se++;
		if(!vis[v]){
			dfs(v);
		}
	}
}
void solve(){
	cin>>n>>m;
	for(int u,v,i=1;i<=m;i++){
		cin>>u>>v;
		g.addedge(u,v);
		g.addedge(v,u);
	}
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			cnt++;
			bk[cnt].fi=bk[cnt].se=0;
			dfs(i);
			bk[cnt].se/=2;
		}
	}
	sort(bk+1,bk+1+cnt);
	ll add=0;
	for(int i=1;i<=cnt;i++){
		// cout<<bk[i].fi<<" "<<bk[i].se<<endl;
		add+=bk[i].fi*(bk[i].fi-1)/2-bk[i].se;
	}
	if(add==0){
		bk[0].fi=bk[1].fi+bk[2].fi;
		bk[0].se=bk[1].se+bk[2].se;
		add=bk[0].fi*(bk[0].fi-1)/2-bk[0].se;
	}
	cout<<add<<endl;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	// cin>>t;
	while(t--){
		solve();
	}

}

J.Minimum Manhattan Distance

题意:给定两个不想交的园 c 1 c_1 c1 c 2 c_2 c2。求在 c 2 c_2 c2里面或者边界上取一点,在 c 1 c_1 c1中均匀去点的最小期望。
思路:均匀!那应该使平均值了,所以只要计算C2中去某个点到达C1圆心的最小曼哈顿距离即可。
可以写出如下公式, d i s ∗ s i n α + d i s ∗ c o s α dis*sin\alpha+dis*cos\alpha dissinα+discosα,当角度为45时达到最大,减小的也最多,所以最小。

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=0;
const ll md=1e9+7;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
struct point{
	double x,y;
};
point a,b,c,d;
point getce(point a,point b){
	point tmp;
	tmp.x=(a.x+b.x)/2;
	tmp.y=(a.y+b.y)/2;
	return tmp;
}
double getdis(point a,point b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void solve(){
	cin>>a.x>>a.y>>b.x>>b.y;
	cin>>c.x>>c.y>>d.x>>d.y;
	point ce1=getce(a,b),ce2=getce(c,d);
	//1 0.5 4.5 3.5
	// cout<<ce1.x<<" "<<ce1.y<<endl;
	// cout<<ce2.x<<" "<<ce2.y<<endl;
	double disce=getdis(ce1,ce2),mh=fabs(ce1.x-ce2.x)+fabs(ce1.y-ce2.y);
	double r1=getdis(a,b)/2,r2=getdis(c,d)/2;
	double mhh=mh-sqrt(2)*r2;
	// printf("%0.10lf\n",mh);
	// printf("%0.10lf\n",r2);
	printf("%0.10lf\n",mhh);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}

}

I.Pa?sWorD

题意:给定长度为n的字符串由大写字母、小写字母、数字和问号组成。小写字母可以变成大写或者小写字母,问号可以变成任何字符(大写字母、小写字母、数字),问可以形成多少不同的字符串,大写字母、小写字母、数字各自至少出现一次且相邻字符不相同?
思路:求方案数,那只能用DP写了(不会容斥)。
f i , v , j , k , l f_{i,v,j,k,l} fi,v,j,k,l为到达第i个位置上面的字符为v,大写字母是否出现(j),小写字母是否出现(k),数字是否出现(l)的方案数。
g i , j , k , l g_{i,j,k,l} gi,j,k,l为到达第i个位置,大写字母是否出现(j),小写字母是否出现(k),数字是否出现(l)的方案数。
每次转移只要g减去特定的f即可。
可以状压,滚动数组优化。赛时写的很屎,哈哈。

//It's better to have sex than to do questions
#include<bits/stdc++.h>
#include<string>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define fi first
#define se second
#define ll long long
#define ull unsigned long long
#define ld long double
using namespace std;
const int N=1e5+5;
const ll md=998244353;
const ll inf=1e18;
const double eps=1e-9;
const double E=2.718281828;
//vector<vector<int>>f(n,vector<int>(m,0));
//cout<<fixed<<setprecision(6)
int n;
string s;
ll f[2][70][8],g[2][8];
void init(int now){
	for(int j=1;j<=26+26+10;j++){
		for(int k=0;k<8;k++){
			f[now][j][k]=0;
		}
	}
	for(int k=0;k<8;k++){
		// f[now][j][k]=0;
		g[now][k]=0;
	}
}
int getk(int x,int v){
	if(v>=1&&v<=26){
		x|=1;
	}else if(v>=27&&v<=26+26){
		x|=2;
	}else if(v>=26+26+1&&v<=26+26+10){
		x|=4;
	}
	return x;
}
void solve(){
	cin>>n;
	cin>>s;
	f[0][0][0]=1;
	g[0][0]=1;
	for(int i=1;i<=n;i++){
		int l,r,add=1;
		if(s[i-1]=='?'){
			l=1,r=26+26+10,add=1;
		}else if(s[i-1]>='a'&&s[i-1]<='z'){
			l=1+s[i-1]-'a',r=27+s[i-1]-'a',add=26;
		}else if(s[i-1]>='A'&&s[i-1]<='Z'){
			r=l=27+s[i-1]-'A';
		}else{
			l=r=53+s[i-1]-'0';
		}
		int now=i%2,pre=now^1;
		init(now);
		// cout<<l<<" "<<r<<" "<<add<<endl;
		for(;l<=r;l+=add){
			for(int k=0;k<8;k++){
				int kk=getk(k,l);
				f[now][l][kk]+=(g[pre][k]-f[pre][l][k]+md)%md,f[now][l][kk]%=md;
				g[now][kk]+=(g[pre][k]-f[pre][l][k]+md)%md,g[now][kk]%=md;
			}
		}
	}
	ll ans=0;
	for(int i=1;i<=26+26+10;i++){
		// cout<<f[n%2][i][7]<<endl;
		ans+=f[n%2][i][7],ans%=md;
	}
	cout<<ans<<endl;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	// cin>>t;
	while(t--){
		solve();
	}
}

G.Spanning Tree

题意:给定操作序列和操作生成的数,操作如下定义:每一次操作分两步,第一步给定两个点,两个点在不同的联通块中。第二步,在a的联通块中随机取一个点v,在b的联通块中随机取一个点u,在v和u之间添加一条边。求形成给定的树的可能性。
思路:
首先,是树的结构。先不考虑合法不合法,经过操作形成的必然是一个树的结构。
钦定1为根进行dfs找到每个节点的父亲,顺便就可以处理出倍增数组,每次操作选择两个点,如果操作合法那么这两个点的连通块在树上是要相邻的,相邻就是通过一条边链接。所以可以找到每个点的最上面的父亲,设为ru,rv,如果ru的父亲与v属于同一联通块,或者rv的父亲和u属于同一联通块,那么便是合法的。进行带权并查集,计算概率。
思路很对,为什么没有写出来?因为操作序列与给定树输入反了,哈哈。让我们大声说
”谢谢Karashi 谢谢Karashi 谢谢Karashi“

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
using namespace std;
const int N=1e6+5;
const ll md=998244353;
const ll inf=1e18;
struct graph
{
	int cnte,hd[N];
	struct edge{
		int v,nt;
	}e[N<<1];
	void addedge(int v,int u){
		e[++cnte].v=u;
		e[cnte].nt=hd[v];
		hd[v]=cnte;
	}
};
graph g;
int n,m;
int anc[N],rk[N];
int val[N],fa[N][21];
ll inv[N];
inline int read()
{
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') 
    {
        x=(x<<3)+(x<<1)+(c^48); //等价于x*10+c-48,使用位运算加速
        c=getchar();
    }
    return x*f;
}
inline void write(int x){
	if(x<0)
        putchar('-'),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
    return;
}
inline int fd(int x){
	if(anc[x]==x){
		return x;
	}
	val[x]+=val[anc[x]];
	return anc[x]=fd(anc[x]);
}
inline void uion(int u,int v){
	int ru=fd(u),rv=fd(v);
	if(ru!=rv){
		// if(rk[ru]<rk[rv]){
		// 	swap(ru,rv);
		// }
		anc[rv]=ru;//rv->ru
		val[ru]+=val[rv];
		// if(rk[ru]==rk[rv])rk[ru]++;
		// val[rv]=0;
	}
}
inline void dfs(int x,int p){
	fa[x][0]=p;
	// cout<<"dfs "<<x<<" "<<p<<endl;
	for(int i=1;i<21;i++){
		fa[x][i]=fa[fa[x][i-1]][i-1];
	}
	for(int i=g.hd[x];i;i=g.e[i].nt){
		int v=g.e[i].v;
		if(v!=p){
			dfs(v,x);
		}
	}
}
inline int fdh(int x){
	int xx=x;
	// cout<<"fdh"<<endl;
	for(int i=20;i>=0;i--){
		if(fa[x][i]!=0&&fd(fa[x][i])==fd(xx)){
			// cout<<fa[x][i]<<endl;
			x=fa[x][i];
		}
	}
	// if(x==0)x=1;
	// cout<<x<<" "<<xx<<endl;
	return x;
}
inline ll ksm(ll a,ll b){
	ll res=1;
	while(b){
		if(b&1)res=res*a%md;
		b>>=1;
		a=a*a%md;
	}
	return res;
}
inline ll getinv(ll a,ll b){
	return ksm(a,b-2);
}
pair<int,int>op[N];
void solve(){
	// cin>>n;
	n=read();
	for(int i=1;i<=n;i++){
		anc[i]=i;
		val[i]=1;
		inv[i]=getinv(i,md);
	}
	for(int i=1;i<n;i++){
		// cin>>op[i].fi>>op[i].se;
		op[i].fi=read();
		op[i].se=read();
	}
	for(int v,u,i=1;i<n;i++){
		// cin>>v>>u;
		v=read();
		u=read();
		g.addedge(u,v);
		g.addedge(v,u);
	}
	dfs(1,0);
	// cout<<"dfs end"<<endl;
	ll ans=1;
	// cout<<fa[3][0]<<endl;
	for(int u,v,i=1;i<n;i++){
		// cin>>u>>v;
		u=op[i].fi;
		v=op[i].se;
		int fu=fdh(u),fv=fdh(v);
		// cout<<fu<<" "<<fa[fu][0]<<" "<<fv<<" "<<fa[fv][0]<<endl;
		if(fd(fa[fu][0])==fd(v)||fd(fa[fv][0])==fd(u)){
			int ru=fd(u),rv=fd(v);
			// cout<<val[ru]<<" "<<val[rv]<<endl;
			ans=ans*inv[val[rv]]%md*inv[val[ru]]%md;
			uion(u,v);
		}else{
			// cout<<"cant"<<endl;
			ans=0;
		}
	}
	// cout<<ans<<"\n";
	write(ans);
	putchar('\n');
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t=1;
	// cout<<(1<<20)<<endl;
	// cin>>t;
	// cout<<getinv(240,md)<<endl;
	while(t--){
		solve();
	}
}

没打好,下次好好打,至少要把能写的写出来。哈哈

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值