Examples

2022-6-24 #5 uoj Goodbye Dingyou

瑶瑶啊,你再整天这样莫名其妙下去,没有任何希望!😅

010 uoj#350 新年的XOR

哈哈,大水题。

根据经典结论,\(1\oplus 2\oplus\cdots\oplus x=\begin{cases}x&x\bmod 4=0\\1&x\bmod 4=1\\x+1&x\bmod 4=2\\0&x\bmod 4=3\end{cases}\)

也就是说,我们能且只能构造出 \(1\),模四余零,模四余三的数之间两两异或的结果。

那么,对于模四的每个余数,都可以很容易构造出一组解。

#include<stdio.h>
int T;
long long n;
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%lld",&n);
		if(n%4==0){
			if(n==0)
				puts("1 3");
			else printf("1 %lld\n",n);
		}
		if(n%4==1){
			if(n==1)
				puts("1 5");
			else printf("2 %lld\n",n^1);
		}
		if(n%4==2){
			if(n==2)
				puts("3 5");
			else printf("2 %lld\n",n);
		}
		if(n%4==3)
			printf("1 %lld\n",n-1);
	}
	return 0;
}

011 uoj#351 新年的叶子

所有直径的中点重合,要么同时在一个点上,要么同时在一个边上。

对于直径中点在点上的情况,我们发现直径长度缩短当且仅当直径中点(以其为根)只有不超过一棵子树存在深度取到最大值。

对于直径中点在边上的情况,直径长度缩短以边为根后,两个点中有一个点子树中深度最大值的叶子都被染黑了。

然后随便算概率吧,复杂度 \(O(n)\)

#include<stdio.h>
#include<vector>
using namespace std;
const int maxn=500005,mod=998244353;
int n,tot,ans,mx,rec,ts,leafs,sum;
int H[maxn],t[maxn],fa[maxn],inv[maxn];
vector<int>v[maxn];
void dfs(int x,int last,int d){
	int leaf=1;
	for(int i=0;i<v[x].size();i++)
		if(v[x][i]!=last)
			leaf=0,dfs(v[x][i],x,d+1);
	fa[x]=last;
	if(d>mx)
		mx=d,rec=x,tot=0;
	if(leaf&&d==mx)
		tot++;
}
int main(){
	scanf("%d",&n);
	for(int i=1,x,y;i<n;i++)
		scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
	mx=0,dfs(1,0,0),mx=0,dfs(rec,0,0);
	if(mx&1){
		int rtx=rec;
		for(int i=1;i<=mx/2;i++)
			rtx=fa[rtx];
		int rty=fa[rtx];
		mx=tot=0,dfs(rtx,rty,0);
		if(tot)
			t[++ts]=tot;
		mx=tot=0,dfs(rty,rtx,0);
		if(tot)
			t[++ts]=tot;
	}
	else{
		int rt=rec;
		for(int i=1;i<=mx/2;i++)
			rt=fa[rt];
		mx/=2;
		for(int i=0;i<v[rt].size();i++){
			tot=0,dfs(v[rt][i],rt,1);
			if(tot)
				t[++ts]=tot;
		}
	}
	for(int i=1;i<=n;i++)
		leafs+=(v[i].size()==1);
	for(int i=1;i<=ts;i++)
		sum+=t[i];
	for(int i=1;i<=n;i++)
		inv[i]=i==1? 1:(mod-1ll*(mod/i)*inv[mod%i]%mod),H[i]=(H[i-1]+1ll*inv[i]*leafs)%mod;
	for(int i=1;i<=ts;i++)
		ans=(ans+H[sum-t[i]])%mod;
	printf("%d\n",(ans-1ll*(ts-1)*H[sum]%mod+mod)%mod);
	return 0;
}

012 uoj#352 新年的五维几何

怎么比上一道题还简单。。。

根据 AGC020F 的套路,我们枚举每个数的整数部分,小数部分枚举其大小排列,然后直接判断就好了。。。

复杂度 \(O((r-l)^nn!n^2)\)

#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=6;
int n,ps;
int l[maxn],r[maxn],a[maxn][maxn],p[maxn],P[maxn],x[maxn],R[maxn];
double ans,d;
void dfs(int t){
	if(t>ps){
		for(int i=1;i<=ps;i++)
			P[i]=i;
		do{
			int flg=1;
			for(int i=1;i<=n;i++)
				for(int j=1;j<=n;j++)
					flg&=(x[i]-x[j]>a[i][j])|(x[i]-x[j]==a[i][j]&&P[R[i]]>=P[R[j]]);
			ans+=flg;
		}while(next_permutation(P+1,P+1+ps));
		return ;
	}
	for(int i=l[p[t]];i<r[p[t]];i++)
		x[p[t]]=i,dfs(t+1);
}
int main(){
	scanf("%d",&n),d=1;
	for(int i=1;i<=n;i++){
		scanf("%d%d",&l[i],&r[i]);
		if(l[i]<r[i])
			p[++ps]=i,R[i]=ps,d*=ps*(r[i]-l[i]);
		else x[i]=l[i];
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&a[i][j]);
	dfs(1);
	printf("%.9lf\n",ans/d);
	return 0;
}

013 uoj#353 新年的代码

dp 细节为什么编了一万年不会……

根据经典结论,我们将 \(R,G,B\) 看作 \(0,1,2\),变换后的串与原串三进制异或值相等。

按照三进制异或值给序列分成尽可能多的对应段,段间显然没有操作,段内操作数量要么是段长,要么是段长减一。(感性上比较显然)

我们发现 \((i,i+1)\) 型操作一定至少一次,而开头对应的操作要么可以放到操作序列开头,要么可以放到操作序列结尾。(在拓扑图中,如果一个度为 \(1\),它要么可以放到拓扑序开头,要么可以放到结尾)

另外,可以发现操作具有可逆性,所以我们可以把放到结尾看成对 \(t\) 进行操作,于是列出 dp:令 \(f_i\) 表示 \(s_{i+1\cdots n}\) 已经被操作成了 \(t_{i+1\cdots n}\),第一个位置被操作成了一个固定字母,能不能用长度减一次操作完成,\(g_i\) 则是将 \(t\)\(s\) 操作的 dp 数组。

然后直接分讨 dp 即可,复杂度 \(O(n)\)

#include<stdio.h>
#include<iostream>
#include<map>
using namespace std;
const int maxn=500005;
int n,ans;
int sum[maxn],a[maxn],b[maxn],f[maxn],g[maxn];
string s,t;
map<char,int>mp;
inline int trans(int a,int b,int c){//ab->c_
	return a==c||a==b||b!=c;
}
int main(){
	scanf("%d",&n),cin>>s>>t,mp['R']=0,mp['G']=1,mp['B']=2;
	for(int i=1;i<=n;i++)
		a[i]=mp[s[i-1]],b[i]=mp[t[i-1]];
	for(int i=1;i<=n;i++){
		int j=i,s=0;
		while(j<=n){
			s=(s+a[j]-b[j]+3)%3;
			if(s%3==0)
				break;
			j++;
		}
		f[j]=g[j]=1,s=(a[j]-b[j]+3)%3;
		for(int k=j-1;k>=i;k--){
			int A=(a[k]+s)%3,B=(b[k]-s+3)%3;
			if(f[k+1]){
				if(trans(B,a[k+1],b[k]))
					f[k]=1;
				if(trans(a[k],a[k+1],A))
					g[k]=1;
			}
			if(g[k+1]){
				if(trans(b[k],b[k+1],B))
					f[k]=1;
				if(trans(A,b[k+1],a[k]))
					g[k]=1;
			}
			s=(s+a[k]-b[k]+3)%3;
		}
		ans+=(j-i+1)-(f[i]|g[i]);
		i=j;
	}
	printf("%d\n",ans);
	return 0;
}

014 uoj#354 新年的投票

非常有意思的题阿!orz hzr。

Sub1:

很容易发现 \({15\choose 7}=6435\) 是比较符合要求的,我们考虑向它凑。

考虑一个这样的策略:如果看到的 \(1\) 数量比 \(0\) 多就认为自己是 \(1\),否则认为自己是 \(0\),计算异或和然后上报。

除了 \(8\times 1+7\times0\) 的情况,其他情况都是数量占优势的数字对应者的投票作为答案,正确性显然。

代码见 Sub2。

Sub3:

两种情况,显然是全 \(0\) 或全 \(1\) 的情况,或者是其中的一种情况。

考虑这个序列的一个极长 \(0\) 前缀,除了全 \(0\) 情况,其余情况最后一个位置都是 \(1\)。同时,很容易分辨一个数是不是在这个全 \(0\) 前缀。

于是,如果一个人前面所有人都是 \(0\),他就认为自己是 \(1\),并给算出来的异或和投 \(2^i\) 张票。

#include<stdio.h>
int main(){
	freopen("vote3.ans","w",stdout);
	for(int i=1;i<=15;i++){
		for(int j=0;j<(1<<14);j++){
			int flg=1;
			for(int k=1;k<i;k++)
				flg&=((j>>(k-1))&1)==0;
			if(flg){
				int v=__builtin_parity(j)^1;
				printf("%d",((v==1? 1:-1)<<(i-1)));
			}
			else printf("0");
			putchar((j==(1<<14)-1)? '\n':' ');
		}
	}
	return 0;
}

Sub2:

不妨继续猜测错误次数,可以发现 \(\frac{2^{15}}{16}=2048\) 恰好符合要求。

为了模仿 Sub3,我们把 \(15\) 个人分成 \(4\) 组,大小分别是 \(1,2,4,8\),一个组对应的数字是其数字的异或和。

直接采用 Sub3 的做法即可做到 \(\frac{1}{16}\) 的错误率。

注意如果要让自己投 \(0\) 票,就需要让自己的成员一半投正一半投负。(第一组显然不会投 \(0\) 票)

#include<stdio.h>
int main(){
	freopen("vote2.ans","w",stdout);
	for(int c=1;c<=4;c++){
		int l=(1<<(c-1)),r=(1<<c)-1;
		for(int i=l;i<=r;i++){
			for(int j=0;j<(1<<14);j++){
				int flg=1,rec=0;
				for(int d=1;d<c;d++){
					int dl=(1<<(d-1)),dr=(1<<d)-1,x=0;
					for(int k=dl;k<=dr;k++)
						x^=(j>>(k-1))&1;
					flg&=(x==0);
				}
				int tot=0,val=1,f=0;
				for(int d=1;d<=4;d++){
					for(int k=1;k<=(1<<(d-1));k++){
						tot++;
						if(f==0&&i==tot){
							f=1,tot--;
							continue;
						}
						if(d!=c)
							val^=(j>>(tot-1))&1;
					}
				}
				int res=(flg==0? (i<=(l+r)/2):val)+48;
				putchar(res);
			}
			putchar('\n');
		}
	}
	return 0;
}

Sub4:

很厉害啊!

对于很多的非传统题,很多时候你都需要对你的策略进行更为严谨地刻画,然后调出最优的参数。

我们考虑上述算法的本质是什么:

一个人的投票策略可以看作一个 \(7\) 元的多项式,

md,调不出来,鸽了。

这里是 64 分的提交记录

posted @ 2022-06-24 16:06  xiaoziyao  阅读(92)  评论(0编辑  收藏  举报