• 2022624 #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 分的提交记录

  • 相关阅读:
    在客户端判断上传文件大小(不支持opera)
    javascript冒泡排序(javascript算法学习)
    提高js性能方法(让js只判断一次)
    ie8本地预览报错的解决
    负载均衡获取客户端IP
    遍历变量里面所有的属性
    HttpWebrequest的使用
    C#调用EnyimMemcached
    MySQL国内省市直辖区
    Log4Net使用
  • 原文地址:https://www.cnblogs.com/xiaoziyao/p/16409272.html
Copyright © 2020-2023  润新知