zoukankan      html  css  js  c++  java
  • Codeforces Round #705 (Div. 2)

    Contest Link

    D - GCD of an Array

    给定一个序列,每次将某个位置乘上 (x) 并询问当前的 (gcd) ,对 (1e9+7) 取模。(n,qleq 2e5) .


    明显是拆因子+线段树……但是可以用 unordered_map/cy

    //Author: RingweEH
    unordered_map<int,map<int,int> >mp,cnt;
    
    void Work( int pos,int x )
    {
    	for ( int i=2; i<=sqrt(x); i++ )
    		while ( x%i==0 )
    		{
    			mp[pos][i]++; cnt[i][mp[pos][i]]++;
    			if ( cnt[i][mp[pos][i]]==n ) ans=ans*i%Mod;
    			x/=i;
    		}
    	if ( x>1 )
    	{
    		mp[pos][x]++; cnt[x][mp[pos][x]]++;
    		if ( cnt[x][mp[pos][x]]==n ) ans=ans*x%Mod;
    	}
    }
    
    int main()
    {
    	n=read(); q=read();
    	for ( int i=1 ;i<=n; i++ ) a[i]=read(),Work(i,a[i]);
    	for ( int pos,x; q; q-- )
    		pos=read(),x=read(),Work(pos,x),printf("%lld
    ",ans );
    
    	return 0;
    }
    

    E - Enormous XOR

    定义 (g(l,r)=xoplus(x+1)oplus cdotsoplus y)(f(l,r)=max{g(x,y)},lleq xleq yleq r) .

    给定 (l,r) ,求 (f(l,r)) .


    奇妙结论题。

    结论:(默认低位开始 (0sim n-1) 位)

    • 如果 (l[n-1] eq r[n-1]) ,那么答案是 (11cdots1)(n) 位)
    • 否则,如果 (r[0]=1) ,答案是 (r) ;如果 (r[0]=0)(lleq r-2) ,答案是 (r+1) ;否则,答案是 (r) .

    Proof

    对于第一种情况显然,因为必然包含了一段 ([0111cdots1,100cdots0]) ( 成段的 (0,1) 都是 (n-1) 个),异或起来就好了。

    • (r) 为奇数

    考虑归纳证明。(f(r-1,r)) 的答案显然是 (r) . 现在考虑从 (f(l,r) o f(l,r+2)) .

    首先,(f(r+1,r+2)=r+2) . 其余段可以分为三种:结尾为 (r+2,r+1,r) . 根据归纳假设,第三类的答案是 (r) . 第一类的答案由一段 ([l,r]) 中的段和一段 ([r+1,r+2]) 组成,后者的异或是 (1) ,所以这一类的答案不会超过 (r+1) .

    对于第二类,假设可以找到大于 (r+2) 的答案。那么一定存在一个 (r+2) 中为 (0) 的位,在答案中为 (1) ,由于 (r+2) 是奇数,这一位不是第 (0) 位。设第一个这一位为 (1) 的数是 (x) ,显然 (x) 必然是个奇数(考虑这一位后面的东西全是 (1) ,因为 (x) 是从大到小第一个出现这一位是 (1) 的),那么 ((x,r+2)) (不包含)的总数是个奇数(后面的位从偶数到 (0) )。而为了让这一位异或结果为 (1) ,从 (x) 往下的段长必然也是奇数(两个 (1) 段之间的 (0) 段长度是偶数),所以答案区间的长度是偶数,也就是说 (n-1) 位异或出来是 (0) ,不可能大于 (r+2) 。所以答案只能是 (r+2) .

    归纳可得,这一种情况的答案是 (r) .

    • (r) 为偶数

    (f(l,r)leq f(l,r+1)=r+1) (因为 (r+1) 是奇数),又由于 (g(r-2,r)=r+1) ,所以 (f(l,r)=r+1) .

    //Author: RingweEH
    int main()
    {
    	scanf( "%d",&n ); scanf("%s%s",a,b );
    	reverse(a,a+n); reverse(b,b+n);
    	if ( a[n-1]!=b[n-1] )
    	{
    		for ( int i=0; i<n; i++ ) printf("1"); return 0;
    	}
    	if ( b[0]=='1' ) { reverse(b,b+n); puts(b); return 0; }
    	for ( int i=0; i<n; i++ ) l[i]=(a[i]=='1'),r[i]=(b[i]=='1');
    	l[0]++;
    	for ( int i=0; i<n; i++ ) l[i+1]+=l[i]/2,l[i]%=2;
    	if ( l[n] ) { reverse(b,b+n); puts(b); return 0; }
    	for ( int i=n-1; i>=0; i-- )
    		if ( r[i]>l[i] )
    		{
    			r[0]++;
    			for ( int i=0; i<n; i++ ) r[i+1]+=r[i]/2,r[i]%=2;
    			for ( int i=(r[n]) ? n : n-1; i>=0; i-- ) printf("%d",r[i] );
    			return 0;
    		}
    	reverse(b,b+n); puts(b);
    
    	return 0;
    }
    

    F - Enchanted Matrix

    给定 (n,m) ,将整个矩阵划分成每个大小为 (r imes c)(r|n,c|m) )的子矩阵,使得它们成对相等。求 ((r,c)) 的方案数。

    交互题。询问格式为 ? h w i1 j1 i2 j2 ,询问大小为 (h imes w) 且不重叠的、左上角分别为 ((i_1,j_1),(i_2,j_2)) 的子矩阵是否相等。询问次数上限为 (3cdotlfloorlog_2(n+m) floor) .


    大致思路:行列显然可以独立求出来,分开考虑各自能分的最大块数然后计算其约数,相乘即可。

    对于求最大块数:先将 (n) (或者 (m) )分解质因数,然后 ( ext{Check}) :当前块长为 (len) ,能否分成 (divi) 个相同的块。如果 (divi) 只有 (2) ,那么直接一次询问就能解决。否则,设 (k)(len/divi) 即每个小块的块长,先比较第一个 (divi/2) 和第二个 (divi/2) ,再比较第一个 (divi/2) 和第二个 (divi/2) 加上 (k) 是否相等。这样做的原理在于,第二次比较的后一个矩形是第一次比较的后一个矩形往后移一个 (k) ,不难证明这样可以直接说明全部小块都相同。

    //Author: RingweEH
    int Query( int len,int p1,int p2 )	//查询整行/整列,另一维长为len,端点p1p2是否相等
    {
    	if ( !fl ) printf("? %d %d %d %d %d %d
    ",len,m,p1,1,p2,1 );
    	else printf("? %d %d %d %d %d %d
    ",n,len,1,p1,1,p2 );
    	fflush(stdout); int x=read(); return x;
    }
    
    //块长是len,分成divi个块,是否相等
    bool Check( int len,int divi )
    {
    	if ( divi==2 ) return Query(len/2,1,len/2+1 );
    	int x=len/divi*(divi/2);
    	return Query(x,1,x+1) && Query(x,1,x+len/divi+1);
    }
    
    //对行/列计算能分的最大块数
    int Work( int x )
    {
    	cnt=0; int nw=x;
    	for ( int i=2; i<=nw; i++ )
    		if ( nw%i==0 )
    		{
    			a[++cnt]=i,b[cnt]=0;
    			while ( nw%i==0 ) b[cnt]++,nw/=i;
    		}
    	int res=1;
    	for ( int i=1; i<=cnt; i++ )
    		for ( int j=1; j<=b[i]; j++ )
    			if ( Check(x/res,a[i]) ) res*=a[i];
    			else break;
    	return res;
    }
    
    int Count( int x )
    {
    	int res=0;
    	for ( int i=1; i<=x; i++ ) res+=(x%i==0);
    	return res;
    }
    
    int main()
    {
    	n=read(); m=read();
    	int ans1=Work(n); fl=1;
    	int ans2=Work(m);
    	printf("! %d
    ",Count(ans1)*Count(ans2) );
    
    	return 0;
    }
    
    天光渐亮。
  • 相关阅读:
    loaded some nib but the view outlet was not set
    指标评比
    IOS DEVELOP FOR DUMMIES
    软件测试题二
    javascript select
    DOM节点类型详解
    mysql操作
    UVA 10055
    solutions for 'No Suitable Driver Found For Jdbc'
    解决git中文乱码问题
  • 原文地址:https://www.cnblogs.com/UntitledCpp/p/14496451.html
Copyright © 2011-2022 走看看