Loading

题解—Math

考场上理论爆零了,可见我有多菜。

这就是一个定理的板子,过了大样例就没有思考,太可恶了。
可见我的数学方面尤其薄弱

定理\(ax+by=c\)有整数解,当且仅当\(gcd(x,y)|c\)
大佬们都说显然,就我一个菜鸡看不出来还得证明。
\(\ \ \ \ \ \ \ ax+by=c\)
\(\ \ gcd(x,y)=g\)
\(\ \ x=tg,y=zg\)
\(\ \ ax+by=atg+bzg=(at+bz)g=c\)
得证

扩展到多元,有解当且进当所有数的\(gcd\)整除\(k\)
也就是说,答案是一个等差数列,公差是\(Gcd_{i=1}^{n}(a[i])\)
我们可以让他不断乘上一个数之后取模,直到出现循环节为止。

但其实这个循环节并不需要暴力去找。
容易发现,因为我们每次加\(gcd\),所以肯定是关于\(gcd\)的因子的等差数列。
有由于我们取模\(k\),所以肯定是关于\(k\)的因子的等差数列。

所以整个数列的公差就是\(gcd(Gcd,k)\)

code


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <assert.h>
#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 = 2e6 + 10 ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch > '9' || ch < '0' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch <= '9' && ch >= '0' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ;  
}

int n , k , a [N] , cd ;
bool fg [N] ;

int gcd( int x , int y ){
	return ( y == 0 ) ? x : gcd( y , x % y ) ;
}

void sc(){
	n = read() , k = read() ;
	for( R i = 1 ; i <= n ; i ++ ) a [i] = read() ; 
}

void work(){
	cd = k ;
	for( R i = 1 ; i <= n ; i ++ )
		cd = gcd( a [i] , cd ) ;
	
	int ans = 0 ;
	for( R i = 0 ; i < k ; i ++ ) if( i % cd == 0 ) ans ++ ;
	printf( "%lld\n" , ans ) ;
	for( R i = 0 ; i < k ; i ++ ) if( i % cd == 0 ) printf( "%lld " , i ) ;
}

signed main(){
	sc() ;
	work() ;
	return 0 ;
}

还有一个小事情,就是考场上因为\(diff\)操作花了很多时间,导致后面时间分配有点不合理。
本质是\(diff\)太垃圾,各种操作他都判断不一样。
所以我们用\(diff-Z\),忽略各种空白。

posted @ 2021-07-11 21:06  Soresen  阅读(45)  评论(0)    收藏  举报