Educational Codeforces Round 64 選作

感受這場比賽題目質量挺高(A 全場最佳),難度也不小。雖然 unr 後就懶得打了。c++

A. Inscribed Figures

題意

給你若干個圖形,每一個圖形爲三角形、圓形或正方形,第 $i$ 個圖形內接於第 $i-1$ 個圖形。問交點是否有限,若有限求交點個數。spa

(題目還有不少細節,具體見原題。)指針

題解

若是兩個同樣的圖形相鄰或正方形和三角形相鄰。code

圓和三角形有 $3$ 個交點,和正方形有 $4$ 個交點。排序

注意若是是 【圓、正方形、三角形】這樣的,最上面有一個交點會重合,答案要減 1 。(出題人一開始也沒注意到,後來重測致使unr)。遞歸

整體來講,這題真的沒什麼意思……遊戲

code

#include<bits/stdc++.h>
using namespace std;
int a[233];
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
#endif
	int n; scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	int ans=0,l=a[1];
	for(int i=2;i<=n;++i)
	{
		int x=a[i];
		if(x==l)
		{
			printf("Infinite");
			return 0;
		}
		int t=x;
		if(x>l) x=l,l=t;
		if(x==1) ans+=l+1;
		if(x==2) {
			printf("Infinite");
			return 0;
		}
		l=t;
	}
	for(int i=3;i<=n;++i) if(a[i-2]==3&&a[i-1]==1&&a[i]==2) --ans;
	printf("Finite\n%d",ans);
}

B. Ugly Pairs

題意

給你一個字符串 $S$ ,重排該字符串使得任意兩個在字母表中相鄰的字符在字符串中不相鄰。若無解輸出 No answer .ci

$T$ 組數據。 $T,|S| \le 100$ 。字符串

題解

去重,只考慮字符的可重集。設 $n$ 爲去重後集合大小。get

容易發現 $n\le 3$ 時會出現無解。

咱們能夠考慮構造。有不少種構造方案能夠解決。對於 $n > 4$ ,一種構造方案是每次選 $i$ 和 $i+n/2$ 放在一塊兒。

那麼對於 $n\le 4$ ,咱們能夠採用手玩或爆搜來解決。

code

#include<bits/stdc++.h>
using namespace std;
const int N=105;
char s[N]; bool flag,vis[30];
int n,m,num[30],ans[N];
void dfs(int u, int now)
{
	if(flag) return ;
	if(now>n)
	{
		flag=true;
		for(int i=1;i<=n;++i)
			while(num[ans[i]]--) putchar(ans[i]+'a');
		puts("");
		return ;
	}
	for(int i=0;i<26;++i)
	{
		if(!vis[i]&&num[i]&&i+1!=u&&i-1!=u)
		{
			vis[i]=true;
			ans[now]=i;
			dfs(i,now+1);
			vis[i]=false;
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("b.in","r",stdin);
#endif
	int T; scanf("%d",&T);
	while(T--)
	{
		flag=false;
		scanf("%s",s+1);
		n=strlen(s+1);
		memset(num,0,sizeof(num));
		memset(vis,false,sizeof(vis));
		for(int i=1;i<=n;++i) ++num[s[i]-'a'];
		sort(s+1,s+1+n);
		n=unique(s+1,s+1+n)-s-1;
		if(n<=4)
		{
			dfs(233,1);
			if(!flag) puts("No answer");
			continue;
		}
		for(int i=1;i<=n>>1;++i)
		{
			while(num[s[i]-'a']--) putchar(s[i]);
			while(num[s[i+(n-1)/2+1]-'a']--) putchar(s[i+(n-1)/2+1]);
		}
		if(n&1) while(num[s[n/2+1]-'a']--) putchar(s[n/2+1]);
		puts("");
	}
}

C. Match Points

題意

給你 $n$ 個點 $x_1,x_2,...,x_n$ 。兩個點 $i,j$ 能配對當且僅當 $|x_i-x_j|\ge z$ 。求最大配對數量。

$n\le 2\cdot 10^5, x_i,z\le 10^9$ 。

題解

首先直接順次匹配確定是錯的,就不解釋了。

考慮二分答案 $y$ 。咱們只要考慮前 $y$ 個數,判斷 $x_i$ 可否和 $x_{n-y+i}$ 匹配便可。

由這個二分答案的作法,咱們能夠進一步得出一個線性作法:咱們能夠把原序列分紅兩半而後順次匹配,用雙指針作一下就好了。

code

#include<bits/stdc++.h>
using namespace std;
inline int gi()
{
	char c; int x=0,f=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
	return x*f;
}
const int N=2e5+5;
int a[N],n,z,ans;
int main()
{
#ifndef ONLINE_JUDGE
	freopen("c.in","r",stdin);
#endif
	n=gi(),z=gi();
	for(int i=1;i<=n;++i) a[i]=gi();
	sort(a+1,a+1+n);
	int l=1,r=n/2+1;
	while(l<=r&&l<=n/2&&r<=n)
	{
		if(a[r]-a[l]>=z) ++ans,++l;
		++r;
	}
	printf("%d",ans);
}

D. 0-1-Tree

題意

給你一棵 $n$ 個點的樹,每條邊標有 0 或 1 。問有多少對點 $(x,y)$ 知足 $x\rightarrow y$ 的路徑上 0 邊不會在 1 邊以後出現。

$n\le 2\cdot 10^5$ 。

題解

先通過 0 邊再通過 1 邊。考慮枚舉分界點,貢獻即爲 僅經過 0 邊與其連通的節點數 * 僅經過 1 邊與其連通的節點數。並查集維護便可。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int gi()
{
	char c; int x=0,f=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
	return x*f;
}
const int N=200005;
int f[2][N],s[2][N];
int findset(int u, int w)
{
	if(f[w][u]==u) return u;
	return f[w][u]=findset(f[w][u],w);
}
void unionset(int u, int v, int w)
{
	int fu=findset(u,w),fv=findset(v,w);
	s[w][fu]+=s[w][fv];
	f[w][fv]=fu;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("d.in","r",stdin);
#endif
	int n=gi();
	for(int i=0;i<2;++i)
		for(int j=1;j<=n;++j) f[i][j]=j,s[i][j]=1;
	for(int i=1;i<n;++i)
	{
		int u=gi(),v=gi(),w=gi();
		unionset(u,v,w);
	}
	long long ans=0;
	for(int i=1;i<=n;++i)
		ans+=1ll*s[0][findset(i,0)]*s[1][findset(i,1)];
	printf("%I64d",ans-n);
}

E. Special Segments of Permutation

題意

給你一個長度爲 $n$ 的排列 $p$ ,詢問有多少個區間 $[l,r]$ ,知足 $\displaystyle p_l+p_r=\max_{i=l}^r p_i$ 。

$n\le 2\cdot 10^5$

題解

考慮最大值分治。對於區間 $[l,r]$ ,rmq 找到最大值 $m$ ,咱們選擇 $[l,m-1]$ 和 $[m+1,r]$ 中長度最小的區間來枚舉邊界點。而後遞歸 $[l,m-1]$ 和 $[m+1,r]$ 。這樣是啓發式合併的複雜度 ,是 $O(n\log n)$ 的 。

code

#include<bits/stdc++.h>
using namespace std;
inline int gi()
{
	char c; int x=0,f=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
	return x*f;
}
const int N=2e5+5;
int f[N][30],p[N],pos[N],lg[N],ans,n;
inline int chmax(int x, int y) {
	return p[x]>p[y]?x:y;
}
inline int getmx(int l, int r)
{
	int t=lg[r-l+1];
	return chmax(f[l][t],f[r-(1<<t)+1][t]);
}
void solve(int l, int r)
{
	if(l>=r) return ;
	int m=getmx(l,r);
	if(m-l<r-m)
		for(int i=l;i<m;++i)
			ans+=(m<=pos[p[m]-p[i]]&&pos[p[m]-p[i]]<=r);
	else
		for(int i=m+1;i<=r;++i)
			ans+=(l<=pos[p[m]-p[i]]&&pos[p[m]-p[i]]<=m);
	solve(l,m-1),solve(m+1,r);
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("e.in","r",stdin);
#endif
	n=gi();
	for(int i=2;i<=n;++i) lg[i]=lg[i-1]+!(i&(i-1));
	for(int i=1;i<=n;++i) p[i]=gi(),pos[p[i]]=f[i][0]=i;
	for(int j=1;(1<<j)<=n;++j)
		for(int i=1;i+(1<<j)-1<=n;++i)
			f[i][j]=chmax(f[i][j-1],f[i+(1<<j-1)][j-1]);
	solve(1,n);
	printf("%d",ans);
}

F. Card Bag

題意

你在玩遊戲。給你 $n$ 張牌,每張牌上有個數字 。你每次從中等機率選出一張牌並扔掉。設你選出的數爲 $x$ ,上一次選出的數爲 $y$ 。若 $x>y$ 你輸, $x=y$ 你贏, $x<y$ 繼續。若牌扔完後遊戲仍未結束則你輸。求你贏的機率。

題解

咱們須要選出一條單升序列,最後再選上序列中的最後一個數。

首先咱們記下每一個數字出現的次數,而後對原序列排序去重。

設 $f(i,j)$ 表示前 $i$ 個數選了 $j$ 個的機率。

$f(i,j)=f(i-1,j)+f(i-1,j-1)\times \frac{x_i}{n-j+1}$

其中 $x_i$ 表示這個數出現的個數。

統計答案的話在中間作一下就好了。

code

#include<bits/stdc++.h>
using namespace std;
inline int gi()
{
	char c; int x=0,f=1;
	for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
	return x*f;
}
const int N=5005,Mod=998244353;
int f[N][N],inv[N],num[N],a[N],n,m,ans;
int main()
{
#ifndef ONLINE_JUDGE
	freopen("f.in","r",stdin);
#endif
	n=m=gi();
	for(int i=1;i<=n;++i) a[i]=gi(),++num[a[i]];
	inv[0]=inv[1]=1;
	for(int i=2;i<=n;++i) inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
	sort(a+1,a+1+n);
	n=unique(a+1,a+1+n)-a-1;
	f[0][0]=1;
	for(int i=1;i<=n;++i)
		for(int j=0;j<=i;++j)
		{
			f[i][j]=1ll*num[a[i]]*inv[m-j+1]%Mod*f[i-1][j-1]%Mod;
			ans=(ans+1ll*(num[a[i]]-1)*inv[m-j]%Mod*f[i][j]%Mod)%Mod;
			f[i][j]=(f[i][j]+f[i-1][j])%Mod;
		}
	printf("%d",ans);
}
相關文章
相關標籤/搜索