Loading

题解—玄学题

只能说我太菜了。

我考场上打的暴力,但是由于太菜没想到只有完全平方数的约数是奇数(这个大家都想到了)。
所以\(nm\ ln(mn)\)求了因子个数,然后暴力的。
最后由于比较贪开大了\(N\),导致被很慢的评测机把分卡没了。

实际上,还有一种方法可以优化连完全平方数都想不出来的菜鸡方法—\(O(n)\)求约数个数。
这个详见我的总结—线性筛及其扩展

我们其实就是求\(\sum d(i*j)\)是多少,但是这个东西并不需要\(O(m)\)枚举。
因为\(i*j\)只有是完全平方数\(d(i*j)\)才是奇数,只有是奇数才对答案有贡献。
所以我们就是想计算,对于给定的一个\(i\)\(i*j(j::1\sim m)\)中有多少是完全平方数。

我们只需要把\(i\)都找到一个数组\(gan[i]\)
表示\(i\)的完全平方因子都被干完之后剩下的数。
之后直接\(\sqrt{(m/gan[i])}\)就是答案。
很显然的,因为只有\(i\)的非完全平方因子和\(j\)的非完全平方因子相同的时候他们的积才是完全平方数。
然后就是求1到\(m\)中有多少个数除\(gan[i]\)是完全平方数。
其中只有\(m/gan[i]\)个数是合法的(剩下的是小数)
并且他们还是从1开始连续的。
所以直接取根号就行。

接下来就是如何求\(gan[i]\)

做法一:暴力

我们可以先把所有的完全平方因子处理出来,然后把所有有完全平方因子的数打一个标记。
对于一个没有完全平方因子的数,我们枚举所有完全平方数,然后把他们的积乘上这个数。
和我考场上打的暴力思路很像(暴力算因子个数)。

复杂度是可以接受的,因为是\(N/4+N/9+N/16+...\)所以不会炸。

做法二:线性筛

可以发现,函数\(Gan(i)\)是一个积性函数,所以可以线性筛线性求。
还是按照套路处理就行了。

记录一个最小质因子出现的次数是奇数还是偶数。

  • 如果这个数是质数,那么把出现次数设置成奇数,值设置成2。
  • 如果一个数被筛到,由于他肯定是被最小质因子筛到的,所以我们讨论一下。
  • 如果\(i%pr[j]==0\)我们把他出现的次数异或一下\(1\),之前是\(1\)就除掉,之前是\(0\)就乘上。
  • 否则直接继承\(i\)\(gan\)在乘上\(pr[j]\),出现次数设置成\(1\)就行了(因为\(i\)里面没有\(pr[j]\),说明是第一次出现)。
线性筛code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define R register int
#define int long 
#define printf Ruusupuu = printf
#define scanf Ruusupuu = scanf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef pair<int , int> PI ;
const int N = 1e7 + 10 ;

inline void of(){ freopen( "c.in" , "r" , stdin ) , freopen( "c.out" , "w" , stdout ) ; }
inline void cf(){ fclose( stdin ) , fclose( stdout ) ; }
inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , mx [N] , gan [N] , pr [N] , top ;
bool fg [N] ; L m ;

void sc(){
	n = read() ; scanf( "%lld" , &m ) ;
}

void work(){
	for( R i = 2 ; i <= n ; i ++ ){
		if( !fg [i] ) pr [++ top] = i , gan [i] = i , mx [i] = 1 ;
		for( R j = 1 ; j <= top && i * pr [j] <= n ; j ++ ){
			fg [i * pr [j]] = 1 ;
			if( i % pr [j] == 0 ){
				if( mx [i] ){
					mx [i * pr [j]] = 0 ;
					gan [i * pr [j]] = gan [i] / pr [j] ;
				}
				else{
					mx [i * pr [j]] = 1 ;
					gan [i * pr [j]] = gan [i] * pr [j] ;
				}
				break ;
			} gan [i * pr [j]] = gan [i] * pr [j] , mx [i * pr [j]] = 1 ;
		} 
	} 
	gan [1] = 1 ; L ans = 0 ;
	for( R i = 1 ; i <= n ; i ++ ){
		L x = m / gan [i] , t = sqrt( x ) ;
		ans += ( t % 2 ) ? -1 : 1 ;
	} printf( "%lld\n" , ans ) ;
}

signed main(){
	//of() ;
	sc() ;
	work() ;
	//cf() ;
	return 0 ;
}
刷表算code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define R register int
#define int long long
#define printf Ruusupuu = printf
#define scanf Ruusupuu = scanf

int Ruusupuu ;

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef pair<int , int> PI ;
const int N = 1e7 + 10 ;

inline void of(){ freopen( "c.in" , "r" , stdin ) , freopen( "c.out" , "w" , stdout ) ; }
inline void cf(){ fclose( stdin ) , fclose( stdout ) ; }
inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int n , m , gan [N] , pp [N] , top ;
bool fg [N] ;

void sc(){
	n = read() , m = read() ;
}

void work(){
	for( R i = 1 ; i < N ; i ++ ){
		int x = sqrt( i ) ;
		gan [i] = 1 ;
		if( x * x == i ) pp [++ top] = i , fg [i] = 1 ;
	} gan [1] = 1 ;
	for( R i = 2 ; i <= top ; i ++ )
		for( R j = 1 ; pp [i] * j < N ; j ++ )
			fg [j * pp [i]] = 1 ;		
		
	for( R i = 1 ; i <= top ; i ++ )
		for( R j = 1 ; pp [i] * j < N ; j ++ ){
			if( fg [j] ) continue ;
			gan [j * pp [i]] *= j ;
		}	
	
	int ans = 0 ;
	for( R i = 1 ; i <= n ; i ++ ){
		int x = m / gan [i] , t = sqrt( x ) ;
		( t % 2 == 0 ) ? ans ++ : ans -- ;	
	}
	printf( "%lld\n" , ans ) ;
}

signed main(){
	//of() ;
	sc() ;
	work() ;
	//cf() ;
	return 0 ;
}
posted @ 2021-07-13 16:38  Soresen  阅读(113)  评论(0)    收藏  举报