快读快输模板:
inline int read ( ) {
char ch = getchar ( ) ;
int x = 0 , f = 1 ;
while ( ch < '0' || ch > '9' ) {
if ( ch == '-' ) f = - 1 ;
ch = getchar ( ) ;
}
while ( '0' <= ch && ch <= '9' ) {
x = x * 10 + ch - '0' ;
ch = getchar ( ) ;
}
return x * f;
}
inline void write ( int x) {
if ( x < 0 ) x = ~ x + 1 , putchar ( '-' ) ;
if ( x > 9 ) write ( x / 10 ) ;
putchar ( x % 10 + '0' ) ;
}
输出后空格
void writespace ( int x)
{
write ( x) ; putchar ( 32 ) ; return ;
}
输出后换行
void writeln ( int x)
{
write ( x) ; putchar ( 10 ) ;
}
inline void print ( __int128 x) {
if ( x< 0 ) {
putchar ( '-' ) ;
x= - x;
}
if ( x> 9 )
print ( x/ 10 ) ;
putchar ( x% 10 + '0' ) ;
}
常用模板:
线段树模板:
void pushup ( int n) {
t[ n] . ma= max ( t[ n<< 1 ] . ma, t[ n<< 1 | 1 ] . ma) ;
t[ n] . mi= min ( t[ n<< 1 ] . mi, t[ n<< 1 | 1 ] . mi) ;
t[ n] . sum= ( t[ n<< 1 ] . sum+ t[ n<< 1 | 1 ] . sum) % mod;
t[ n] . mul= ( t[ n<< 1 ] . mul+ t[ n<< 1 | 1 ] . mul) % mod;
}
void build ( int l, int r, int n) {
if ( l== r) {
t[ n] . l= l, t[ n] . r= r;
t[ n] . sum= t[ n] . mi= t[ n] . ma= a[ l] ;
t[ n] . mul= a[ l] * a[ l] % mod;
return ;
}
t[ n] . l= l, t[ n] . r= r;
int mid= ( l+ r) >> 1 ;
build ( l, mid, n<< 1 ) ;
build ( mid+ 1 , r, n<< 1 | 1 ) ;
pushup ( n) ;
}
void update ( int l, int r, int n, int pos, int val) {
if ( l== r&& l== pos) {
t[ n] . sum= t[ n] . mi= t[ n] . ma= val;
t[ n] . mul= val* val% mod;
a[ pos] = val;
return ;
}
int mid= ( l+ r) >> 1 ;
if ( pos<= mid)
update ( l, mid, n<< 1 , pos, val) ;
else
update ( mid+ 1 , r, n<< 1 | 1 , pos, val) ;
pushup ( n) ;
}
ll ask ( int l, int r, int n, ll k) {
ll ans= 0 ;
if ( t[ n] . ma< k) {
ans= ( ( ( ( ll) ( r- l+ 1 ) * k% mod* k% mod+ t[ n] . mul) % mod- 2ll * k% mod* t[ n] . sum% mod) + mod) % mod;
} else if ( t[ n] . ma>= k&& k> t[ n] . mi) {
int mid= ( l+ r) >> 1 ;
ans= ( ask ( l, mid, n<< 1 , k) % mod+ ask ( mid+ 1 , r, n<< 1 | 1 , k) % mod) % mod;
}
return ans% mod;
}
质数模板:
1 、判断是否是质数
bool isPrime ( long long n) {
if ( n <= 1 ) return false ;
if ( n == 2 || n == 3 ) return true ;
if ( n % 6 != 1 && n % 6 != 5 ) return false ;
for ( long long i = 5 ; i * i <= n; i += 6 ) {
if ( n % i == 0 || n % ( i + 2 ) == 0 ) return false ;
}
return true ;
}
2 、埃氏筛
inline void isPrime ( int n) {
memset ( book, true , n) ;
for ( long long i = 2 ; i<= n; i++ ) {
if ( book[ i] ) {
prime[ ++ cnt] = i;
for ( long long j = i * i; j < n; j += i) book[ j] = false ;
}
}
}
3 、线性筛
inline void Prime ( int n) {
int cnt= 0 ;
memset ( b, true , sizeof ( b) ) ;
b[ 0 ] = b[ 1 ] = 0 ;
for ( int i = 2 ; i<= n; i++ ) {
if ( book[ i] ) prime[ ++ cnt] = i;
for ( int j = 1 ; j <= cnt&& i* prime[ j] <= n; j++ ) {
book[ i* prime[ j] ] = false ;
if ( i% prime[ j] == 0 )
break ;
}
}
}
4 、分解质因数
vector< long long > fac;
void primeFactors ( long long n) {
fac. clear ( ) ;
long long i = 2 ;
while ( i * i <= n) {
while ( n % i == 0 ) {
fac. push_back ( i) ;
n /= i;
}
i++ ;
}
if ( n > 1 ) fac. push_back ( n) ;
for ( int i= 0 ; i< fac. size ( ) - 1 ; i++ ) printf ( "%lld*" , fac[ i] ) ;
printf ( "%lld" , fac[ fac. size ( ) - 1 ] ) ;
}
求逆元模板:
const long long mod = 1e9 + 7 ;
long long fastpow ( long long x, long long y) {
x %= mod;
long long res = 1 ;
while ( y) {
if ( y & 1 ) res = res * x % mod;
y >>= 1 ;
x = x * x % mod;
}
return res;
}
long long inv ( long long n) {
return fastpow ( n, mod - 2 ) % mod;
}
组合数模板:(预处理加逆元)
long long fac[ MAXN] ;
const long long mod = 1e9 + 7 ;
long long fastpow ( long long x, long long y) {
x %= mod;
long long res = 1 ;
while ( y) {
if ( y & 1 ) res = res * x % mod;
y >>= 1 ;
x = x * x % mod;
}
return res;
}
void init ( ) {
fac[ 0 ] = 1 ;
for ( int i= 1 ; i< MAXN; i++ ) fac[ i] = fac[ i- 1 ] * i% mod;
}
long long C ( int n, int m) {
return fac[ m] * fastpow ( fac[ n] , mod- 2 ) % mod* fastpow ( fac[ m- n] , mod- 2 ) % mod;
}
常用库函数:
# include <algorithm>
sort ( 起始地址,结束地址,排序方式)
__gcd ( 第一个整数,第二个整数)
max ( 第一个数,第二个数)
swap ( 第一个变量,第二个变量)
unique ( 起始地址,结束地址)
lower_bound ( 起始地址,结束地址,变量)
upper_bound ( 起始地址,结束地址,变量)
next_permutation ( 起始地址,结束地址)
# include <cstring>
strlen ( 字符串首地址)
memset ( 首地址,变量值,长度)
memcpy ( 被拷贝数组首地址,拷贝数组首地址,长度)
# include <cmath>
fabs ( 数字)
sqrt ( 数字)
pow ( 底数,指数)
cbrt ( 数字)
常用数据结构:
# include <vector>
vector< int > arr;
vector< int > arr[ 10 ] ;
arr. push_back ( 变量)
arr. size ( )
arr. insert ( 地址,变量)
arr. erase ( 地址)
arr. clear ( )
arr. begin ( )
arr. end ( )
# include <queue>
queue< int > q;
q. empty ( )
q. size ( )
q. push ( 变量)
q. front ( )
q. pop ( )
priority_queue< int > q;
q. empty ( )
q. size ( )
q. push ( 变量)
q. top ( )
q. pop ( )
# include <stack>
stack< int > st;
st. empty ( )
q. size ( )
q. push ( 变量)
q. top ( )
q. pop ( )
# include <map>
map< int , int > mp;
mp. count ( 变量)
mp[ 变量]
# include <unordered_map>
unordered_map< int , int > mp;
# include <set>
set< int > s;
s. size ( )
s. find ( 变量)
s. insert ( 变量)
s. erase ( 地址)
Java里的高精度
import java. math. BigInteger;
import java. util. Scanner;
public class Main {
public static void main ( String[ ] args) {
BigInteger a, b;
Scanner scanner= new Scanner ( System. in) ;
while ( scanner. hasNext ( ) ) {
a= scanner. nextBigInteger ( ) ;
b= scanner. nextBigInteger ( ) ;
System. out. println ( a. multiply ( b) ) ;
}
}
}
矩阵快速幂:
typedef long long ll;
const int mod = 1e9 + 7 ;
const int MAXN = 10005 ;
struct Mat {
ll m[ MAXN] [ MAXN] ;
} ans, a;
Mat Mul ( Mat a, Mat b, int n) {
Mat c;
memset ( c. m, 0 , sizeof ( c. m) ) ;
for ( int i = 1 ; i <= n; i++ )
for ( int j = 1 ; j <= n; j++ )
for ( int k = 1 ; k <= n; k++ )
c. m[ i] [ j] = ( c. m[ i] [ j] + ( a. m[ i] [ k] * b. m[ k] [ j] ) % mod) % mod;
return c;
}
Mat _power ( Mat a, int b, int n) {
for ( int i = 1 ; i <= n; i++ )
ans[ i] [ i] = 1 ;
while ( b) {
if ( b & 1 )
ans = Mul ( ans, a, n) ;
a = Mul ( a, a, n) ;
b >>= 1 ;
}
return ans;
}
MST(最小生成树)模板
# include <cstdio>
# include <cstring>
# include <algorithm>
# include <vector>
using namespace std;
# define N 1002
struct node {
int u, v, w;
node ( ) { }
node ( int _u, int _v, int _w) : u ( _u) , v ( _v) , w ( _w) { }
} ;
vector< node> edge;
int n, m, f[ N] ;
bool cmp ( const node & x, const node & y) {
return x. w < y. w;
}
int find_set ( int x) {
if ( f[ x] == x) return x;
return f[ x] = find_set ( f[ x] ) ;
}
int Kruskal ( ) {
sort ( edge. begin ( ) , edge. end ( ) , cmp) ;
for ( int i= 1 ; i<= n; i++ ) f[ i] = i;
int ans = 0 ;
for ( int i= 0 , u, v, w; i< edge. size ( ) ; i++ ) {
u = edge[ i] . u, v = edge[ i] . v, w = edge[ i] . w;
u = find_set ( u) , v = find_set ( v) ;
if ( u == v) continue ;
f[ u] = v;
ans += w;
}
return ans;
}
int main ( ) {
while ( scanf ( "%d%d" , & n, & m) == 2 ) {
edge. clear ( ) ;
for ( int i= 0 , a, b, c; i< m; i++ ) {
scanf ( "%d%d%d" , & a, & b, & c) ;
edge. push_back ( node ( a, b, c) ) ;
}
printf ( "%d\n" , Kruskal ( ) ) ;
}
return 0 ;
}
# include <cstdio>
# include <cstring>
# include <vector>
# include <algorithm>
using namespace std;
# define N 1003
# define inf 0x3f3f3f3f
struct node {
int v, w;
node ( ) { }
node ( int _v, int _w) : v ( _v) , w ( _w) { }
} ;
vector< node> g[ N] ;
int n, m, d[ N] ;
bool vis[ N] ;
int prim ( ) {
memset ( vis, false , sizeof ( vis) ) ;
memset ( d, 0x3f , sizeof ( d) ) ;
int ans = d[ 1 ] = 0 ;
for ( int i= 0 ; i< n; i++ ) {
int k = 0 , mi = inf;
for ( int j= 1 ; j<= n; j++ ) if ( ! vis[ j] && d[ j] < mi)
mi = d[ j] , k = j;
if ( k == 0 ) break ;
vis[ k] = true ;
ans += mi;
for ( int j= 0 , u; j< g[ k] . size ( ) ; j++ )
if ( ! vis[ u = g[ k] [ j] . v] && d[ u] > g[ k] [ j] . w)
d[ u] = g[ k] [ j] . w;
}
return ans;
}
int main ( ) {
while ( scanf ( "%d%d" , & n, & m) == 2 ) {
for ( int i= 0 ; i<= n; i++ ) g[ i] . clear ( ) ;
for ( int i= 0 , a, b, c; i< m; i++ ) {
scanf ( "%d%d%d" , & a, & b, & c) ;
g[ a] . push_back ( node ( b, c) ) ;
g[ b] . push_back ( node ( a, c) ) ;
}
printf ( "%d\n" , prim ( ) ) ;
}
return 0 ;
}
求逆序对(归并排序、树状数组)
# include <bits/stdc++.h>
using namespace std;
int n, a[ 100005 ] , tmpA[ 100005 ] , cnt = 0 ;
void merge_sort ( int l, int r, int * A) {
if ( l >= r) return ;
int mid = ( l + r) >> 1 ;
merge_sort ( l, mid, A) ;
merge_sort ( mid + 1 , r, A) ;
int pl = l, pr = mid + 1 , tmpp = 0 ;
while ( pl <= mid && pr <= r) {
if ( A[ pl] <= A[ pr] ) tmpA[ tmpp++ ] = A[ pl++ ] ;
else tmpA[ tmpp++ ] = A[ pr++ ] , cnt += mid - pl + 1 ;
}
while ( pl <= mid) tmpA[ tmpp++ ] = A[ pl++ ] ;
while ( pr <= r) tmpA[ tmpp++ ] = A[ pr++ ] ;
for ( int i = 0 ; i < tmpp; i++ ) A[ i + l] = tmpA[ i] ;
}
int main ( ) {
scanf ( "%d" , & n) ;
for ( int i = 1 ; i <= n; i++ ) scanf ( "%d" , & a[ i] ) ;
merge_sort ( 1 , n, a) ;
printf ( "%d\n" , cnt) ;
return 0 ;
}
# include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5 ;
int N;
int arr[ MAXN] ;
long long cnt= 0 ;
int lowbit ( int x) {
return x& ( - x) ;
}
int getsum ( int x) {
int sum= 0 ;
for ( int i= x; i; i-= lowbit ( i) ) sum+= a[ i] ;
return sum;
}
void update ( int x) {
for ( int i= x; i<= N; i+= lowbit ( i) ) a[ i] ++ ;
}
int main ( )
{
scanf ( "%d" , & N) ;
for ( int i= 1 ; i<= N; i++ )
update ( arr[ i] ) , cnt+= i- getsum ( arr[ i] ) ;
printf ( "%lld" , cnt) ;
return 0 ;
}
最大平均子序列
# include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 ;
int arr[ MAXN + 5 ] ;
double sum[ MAXN + 5 ] ;
int n, m;
bool check ( double avg)
{
for ( int i = 1 ; i <= n; ++ i) sum[ i] = sum[ i - 1 ] + arr[ i] - avg;
double minv = 0 ;
for ( int i = m; i <= n; ++ i) {
minv = min ( minv, sum[ i - m] ) ;
if ( sum[ i] >= minv) return true ;
}
return false ;
}
int main ( )
{
scanf ( "%d %d" , & n, & m) ;
double l = 0 , r = 0 ;
for ( int i = 1 ; i <= n; ++ i) {
scanf ( "%d" , arr + i) ;
r = max ( r, double ( arr[ i] ) ) ;
l = min ( l, double ( arr[ i] ) ) ;
}
while ( r - l > 1e-5 ) {
double mid = ( l + r) / 2 ;
if ( check ( mid) ) l = mid;
else r = mid;
}
printf ( "%.f\n" , r) ;
return 0 ;
}
最大子序列和
1. 穷举法
算法思想:算出每个子序列的和,即算出序列中第i个到第j个数的和( j>= i) ,并进行比较
算法:
public static int maxSubSum1 ( int [ ] a) {
int maxSum = 0 ;
int sum;
for ( int i = 0 ; i < a. length; i++ ) {
for ( int j = i; j < a. length; j++ ) {
sum = 0 ;
for ( int k = i; k <= j; k++ ) {
sum += a[ k] ;
}
if ( sum > maxSum) {
maxSum = sum;
}
}
}
return maxSum;
}
运行时间为O ( N^ 3 )
2. 对上述第一个算法的改进
算法思想:第一个算法的第三个for 循环中有大量不必要的重复计算,如:计算i到j的和,然而i到j- 1 的和在前一次的循环中已经计算过,无需重复计算,故该for 循环可以去掉
算法:
public static int maxSubSum2 ( int [ ] a) {
int maxSum = 0 ;
int sum;
for ( int i = 0 ; i < a. length; i++ ) {
sum = 0 ;
for ( int j = i; j < a. length; j++ ) {
sum += a[ j] ;
if ( sum > maxSum) {
maxSum = sum;
}
}
}
return maxSum;
}
运行时间为O ( N^ 2 )
3. 分而治之
算法思想:把问题分成两个大致相等的子问题,然后递归地对它们求解,这是“分”的部分。“治”阶段将两个子问题的解修补到一起并可能再做些少量的附加工作,最后得到整个问题的解。
在该问题中,如果把序列从中间分为两部分,那么最大子序列和可能在三处出现,要么整个出现在输入数据的左半部,要么整个出现在右半部,要么跨越分界线。前两种情况可以递归求解,第三种情况的最大和可以通过求出前半部分(包括前半部分的最后一个元素)的最大和以及后半部分(包含后半部分的第一个元素)的最大和而得到,此时将两个和相加。
算法:
public static int maxSubSum3 ( int [ ] a, int left, int right) {
if ( left == right) {
if ( a[ left] > 0 ) {
return a[ left] ;
} else {
return 0 ;
}
}
int center = ( left + right) / 2 ;
int maxLeftSum = maxSubSum3 ( a, left, center) ;
int maxRightSum = maxSubSum3 ( a, center + 1 , right) ;
int maxLeftBorderSum = 0 , leftBorderSum = 0 ;
for ( int i = center; i >= left; i-- ) {
leftBorderSum += a[ i] ;
if ( leftBorderSum > maxLeftBorderSum) {
maxLeftBorderSum = leftBorderSum;
}
}
int maxRightBorderSum = 0 , rightBorderSum = 0 ;
for ( int i = center + 1 ; i <= right; i++ ) {
rightBorderSum += a[ i] ;
if ( rightBorderSum > maxRightBorderSum) {
maxRightBorderSum = rightBorderSum;
}
}
int maxBorderSum = maxLeftBorderSum + maxRightBorderSum;
return maxBorderSum > maxLeftSum ? maxBorderSum > maxRightSum ? maxBorderSum : maxRightSum
: maxLeftSum > maxRightSum ? maxLeftSum : maxRightSum;
}
运行时间O ( N* logN)
4. 最优起点
算法思想:设a[ i] 为和最大序列的起点,则如果a[ i] 是负的,那么它不可能代表最优序列的起点,因为任何包含a[ i] 作为起点的子序列都可以通过a[ i+ 1 ] 作起点而得到改进。
类似的,任何负的子序列也不可能是最优子序列的前缀。
算法:
public static int maxSubSum4 ( int [ ] a) {
int maxSum= 0 , sum= 0 ;
for ( int i= 0 ; i< a. length; i++ ) {
sum+= a[ i] ;
if ( sum> maxSum) {
maxSum= sum;
} else if ( sum< 0 ) {
sum= 0 ;
}
}
return maxSum;
}
运行时间:O ( N)
高精度模板
高精度加法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:倒置相加再还原。
算法复杂度:o ( n)
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int L= 110 ;
string add ( string a, string b)
{
string ans;
int na[ L] = { 0 } , nb[ L] = { 0 } ;
int la= a. size ( ) , lb= b. size ( ) ;
for ( int i= 0 ; i< la; i++ ) na[ la- 1 - i] = a[ i] - '0' ;
for ( int i= 0 ; i< lb; i++ ) nb[ lb- 1 - i] = b[ i] - '0' ;
int lmax= la> lb? la: lb;
for ( int i= 0 ; i< lmax; i++ ) na[ i] += nb[ i] , na[ i+ 1 ] += na[ i] / 10 , na[ i] %= 10 ;
if ( na[ lmax] ) lmax++ ;
for ( int i= lmax- 1 ; i>= 0 ; i-- ) ans+= na[ i] + '0' ;
return ans;
}
int main ( )
{
string a, b;
while ( cin>> a>> b) cout<< add ( a, b) << endl;
return 0 ;
}
高精度减法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:倒置相减再还原。
算法复杂度:o ( n)
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int L= 110 ;
string sub ( string a, string b)
{
string ans;
int na[ L] = { 0 } , nb[ L] = { 0 } ;
int la= a. size ( ) , lb= b. size ( ) ;
for ( int i= 0 ; i< la; i++ ) na[ la- 1 - i] = a[ i] - '0' ;
for ( int i= 0 ; i< lb; i++ ) nb[ lb- 1 - i] = b[ i] - '0' ;
int lmax= la> lb? la: lb;
for ( int i= 0 ; i< lmax; i++ )
{
na[ i] -= nb[ i] ;
if ( na[ i] < 0 ) na[ i] += 10 , na[ i+ 1 ] -- ;
}
while ( ! na[ -- lmax] && lmax> 0 ) ; lmax++ ;
for ( int i= lmax- 1 ; i>= 0 ; i-- ) ans+= na[ i] + '0' ;
return ans;
}
int main ( )
{
string a, b;
while ( cin>> a>> b) cout<< sub ( a, b) << endl;
return 0 ;
}
高精度乘法
高精度乘高精度的朴素算法
算法思想:倒置相乘,然后统一处理进位,再还原。
算法复杂度:o ( n^ 2 )
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int L= 110 ;
string mul ( string a, string b)
{
string s;
int na[ L] , nb[ L] , nc[ L] , La= a. size ( ) , Lb= b. size ( ) ;
fill ( na, na+ L, 0 ) ; fill ( nb, nb+ L, 0 ) ; fill ( nc, nc+ L, 0 ) ;
for ( int i= La- 1 ; i>= 0 ; i-- ) na[ La- i] = a[ i] - '0' ;
for ( int i= Lb- 1 ; i>= 0 ; i-- ) nb[ Lb- i] = b[ i] - '0' ;
for ( int i= 1 ; i<= La; i++ )
for ( int j= 1 ; j<= Lb; j++ )
nc[ i+ j- 1 ] += na[ i] * nb[ j] ;
for ( int i= 1 ; i<= La+ Lb; i++ )
nc[ i+ 1 ] += nc[ i] / 10 , nc[ i] %= 10 ;
if ( nc[ La+ Lb] ) s+= nc[ La+ Lb] + '0' ;
for ( int i= La+ Lb- 1 ; i>= 1 ; i-- )
s+= nc[ i] + '0' ;
return s;
}
int main ( )
{
string a, b;
while ( cin>> a>> b) cout<< mul ( a, b) << endl;
return 0 ;
}
高精度乘高精度FFT优化算法
算法思想:将两个高精度乘数每个数位上的数视为多项式对应的系数,用o ( n* log ( n) ) 的复杂度转成点值形式,再利用o ( n) 的复杂度相乘,最后对点值进行差值,用o ( n* log ( n) ) 的复杂度还原成多项式的形式,即原来的形式。
算法复杂度:o ( n* log ( n) )
# include <iostream>
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <map>
# include <queue>
# include <set>
# include <vector>
using namespace std;
# define L ( x) ( 1 << ( x) )
const double PI = acos ( - 1.0 ) ;
const int Maxn = 133015 ;
double ax[ Maxn] , ay[ Maxn] , bx[ Maxn] , by[ Maxn] ;
char sa[ Maxn/ 2 ] , sb[ Maxn/ 2 ] ;
int sum[ Maxn] ;
int x1[ Maxn] , x2[ Maxn] ;
int revv ( int x, int bits)
{
int ret = 0 ;
for ( int i = 0 ; i < bits; i++ )
{
ret <<= 1 ;
ret |= x & 1 ;
x >>= 1 ;
}
return ret;
}
void fft ( double * a, double * b, int n, bool rev)
{
int bits = 0 ;
while ( 1 << bits < n) ++ bits;
for ( int i = 0 ; i < n; i++ )
{
int j = revv ( i, bits) ;
if ( i < j)
swap ( a[ i] , a[ j] ) , swap ( b[ i] , b[ j] ) ;
}
for ( int len = 2 ; len <= n; len <<= 1 )
{
int half = len >> 1 ;
double wmx = cos ( 2 * PI / len) , wmy = sin ( 2 * PI / len) ;
if ( rev) wmy = - wmy;
for ( int i = 0 ; i < n; i += len)
{
double wx = 1 , wy = 0 ;
for ( int j = 0 ; j < half; j++ )
{
double cx = a[ i + j] , cy = b[ i + j] ;
double dx = a[ i + j + half] , dy = b[ i + j + half] ;
double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
a[ i + j] = cx + ex, b[ i + j] = cy + ey;
a[ i + j + half] = cx - ex, b[ i + j + half] = cy - ey;
double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
wx = wnx, wy = wny;
}
}
}
if ( rev)
{
for ( int i = 0 ; i < n; i++ )
a[ i] /= n, b[ i] /= n;
}
}
int solve ( int a[ ] , int na, int b[ ] , int nb, int ans[ ] )
{
int len = max ( na, nb) , ln;
for ( ln= 0 ; L ( ln) < len; ++ ln) ;
len= L ( ++ ln) ;
for ( int i = 0 ; i < len ; ++ i)
{
if ( i >= na) ax[ i] = 0 , ay[ i] = 0 ;
else ax[ i] = a[ i] , ay[ i] = 0 ;
}
fft ( ax, ay, len, 0 ) ;
for ( int i = 0 ; i < len; ++ i)
{
if ( i >= nb) bx[ i] = 0 , by[ i] = 0 ;
else bx[ i] = b[ i] , by[ i] = 0 ;
}
fft ( bx, by, len, 0 ) ;
for ( int i = 0 ; i < len; ++ i)
{
double cx = ax[ i] * bx[ i] - ay[ i] * by[ i] ;
double cy = ax[ i] * by[ i] + ay[ i] * bx[ i] ;
ax[ i] = cx, ay[ i] = cy;
}
fft ( ax, ay, len, 1 ) ;
for ( int i = 0 ; i < len; ++ i)
ans[ i] = ( int ) ( ax[ i] + 0.5 ) ;
return len;
}
string mul ( string sa, string sb)
{
int l1, l2, l;
int i;
string ans;
memset ( sum, 0 , sizeof ( sum) ) ;
l1 = sa. size ( ) ;
l2 = sb. size ( ) ;
for ( i = 0 ; i < l1; i++ )
x1[ i] = sa[ l1 - i - 1 ] - '0' ;
for ( i = 0 ; i < l2; i++ )
x2[ i] = sb[ l2- i- 1 ] - '0' ;
l = solve ( x1, l1, x2, l2, sum) ;
for ( i = 0 ; i< l || sum[ i] >= 10 ; i++ )
{
sum[ i + 1 ] += sum[ i] / 10 ;
sum[ i] %= 10 ;
}
l = i;
while ( sum[ l] <= 0 && l> 0 ) l-- ;
for ( i = l; i >= 0 ; i-- ) ans+= sum[ i] + '0' ;
return ans;
}
int main ( )
{
cin. sync_with_stdio ( false ) ;
string a, b;
while ( cin>> a>> b) cout<< mul ( a, b) << endl;
return 0 ;
}
高精度乘单精度
算法思想:倒置相乘,然后统一处理进位,再还原。
算法复杂度:o ( n)
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int L= 100005 ;
int na[ L] ;
string mul ( string a, int b)
{
string ans;
int La= a. size ( ) ;
fill ( na, na+ L, 0 ) ;
for ( int i= La- 1 ; i>= 0 ; i-- ) na[ La- i- 1 ] = a[ i] - '0' ;
int w= 0 ;
for ( int i= 0 ; i< La; i++ ) na[ i] = na[ i] * b+ w, w= na[ i] / 10 , na[ i] = na[ i] % 10 ;
while ( w) na[ La++ ] = w% 10 , w/= 10 ;
La-- ;
while ( La>= 0 ) ans+= na[ La-- ] + '0' ;
return ans;
}
int main ( )
{
string a;
int b;
while ( cin>> a>> b) cout<< mul ( a, b) << endl;
return 0 ;
}
高精度除法
高精度除高精度
算法思想:倒置,试商,高精度减法。
算法复杂度:o ( n^ 2 )
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int L= 110 ;
int sub ( int * a, int * b, int La, int Lb)
{
if ( La< Lb) return - 1 ;
if ( La== Lb)
{
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( a[ i] > b[ i] ) break ;
else if ( a[ i] < b[ i] ) return - 1 ;
}
for ( int i= 0 ; i< La; i++ )
{
a[ i] -= b[ i] ;
if ( a[ i] < 0 ) a[ i] += 10 , a[ i+ 1 ] -- ;
}
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( a[ i] ) return i+ 1 ;
return 0 ;
}
string div ( string n1, string n2, int nn)
{
string s, v;
int a[ L] , b[ L] , r[ L] , La= n1. size ( ) , Lb= n2. size ( ) , i, tp= La;
fill ( a, a+ L, 0 ) ; fill ( b, b+ L, 0 ) ; fill ( r, r+ L, 0 ) ;
for ( i= La- 1 ; i>= 0 ; i-- ) a[ La- 1 - i] = n1[ i] - '0' ;
for ( i= Lb- 1 ; i>= 0 ; i-- ) b[ Lb- 1 - i] = n2[ i] - '0' ;
if ( La< Lb || ( La== Lb && n1< n2) ) {
return n1; }
int t= La- Lb;
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( i>= t) b[ i] = b[ i- t] ;
else b[ i] = 0 ;
Lb= La;
for ( int j= 0 ; j<= t; j++ )
{
int temp;
while ( ( temp= sub ( a, b+ j, La, Lb- j) ) >= 0 )
{
La= temp;
r[ t- j] ++ ;
}
}
for ( i= 0 ; i< L- 10 ; i++ ) r[ i+ 1 ] += r[ i] / 10 , r[ i] %= 10 ;
while ( ! r[ i] ) i-- ;
while ( i>= 0 ) s+= r[ i-- ] + '0' ;
i= tp;
while ( ! a[ i] ) i-- ;
while ( i>= 0 ) v+= a[ i-- ] + '0' ;
if ( v. empty ( ) ) v= "0" ;
if ( nn== 1 ) return s;
if ( nn== 2 ) return v;
}
int main ( )
{
string a, b;
while ( cin>> a>> b) cout<< div ( a, b, 1 ) << endl;
return 0 ;
}
高精度除单精度
算法思想:模拟手工除法。
算法复杂度:o ( n)
# include <iostream>
# include <algorithm>
using namespace std;
string div ( string a, int b)
{
string r, ans;
int d= 0 ;
if ( a== "0" ) return a;
for ( int i= 0 ; i< a. size ( ) ; i++ )
{
r+= ( d* 10 + a[ i] - '0' ) / b+ '0' ;
d= ( d* 10 + ( a[ i] - '0' ) ) % b;
}
int p= 0 ;
for ( int i= 0 ; i< r. size ( ) ; i++ )
if ( r[ i] != '0' ) { p= i; break ; }
return r. substr ( p) ;
}
int main ( )
{
string a;
int b;
while ( cin>> a>> b)
{
cout<< div ( a, b) << endl;
}
return 0 ;
}
高精度取模
高精度对高精度取模
算法思想:利用( a+ b) % c= a% c+ b% c。
算法复杂度:o ( n)
# include <iostream>
# include <algorithm>
using namespace std;
int mod ( string a, int b)
{
int d= 0 ;
for ( int i= 0 ; i< a. size ( ) ; i++ ) d= ( d* 10 + ( a[ i] - '0' ) ) % b;
return d;
}
int main ( )
{
string a;
int b;
while ( cin>> a>> b)
{
cout<< mod ( a, b) << endl;
}
return 0 ;
}
高精度对单精度取模
算法思想:利用( a+ b) % c= a% c+ b% c。
算法复杂度:o ( n)
# include <iostream>
# include <algorithm>
using namespace std;
int mod ( string a, int b)
{
int d= 0 ;
for ( int i= 0 ; i< a. size ( ) ; i++ ) d= ( d* 10 + ( a[ i] - '0' ) ) % b;
return d;
}
int main ( )
{
string a;
int b;
while ( cin>> a>> b)
{
cout<< mod ( a, b) << endl;
}
return 0 ;
}
高精度阶乘
算法思想:利用( a+ b) % c= a% c+ b% c。
算法复杂度:o ( n)
# include <iostream>
# include <algorithm>
using namespace std;
int mod ( string a, int b)
{
int d= 0 ;
for ( int i= 0 ; i< a. size ( ) ; i++ ) d= ( d* 10 + ( a[ i] - '0' ) ) % b;
return d;
}
int main ( )
{
string a;
int b;
while ( cin>> a>> b)
{
cout<< mod ( a, b) << endl;
}
return 0 ;
}
高精度幂
算法思想:FFT高精乘+ 二分求幂。
算法复杂度:o ( n* log ( n) * log ( m) )
# include <iostream>
# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <map>
# include <queue>
# include <set>
# include <vector>
using namespace std;
# define L ( x) ( 1 << ( x) )
const double PI = acos ( - 1.0 ) ;
const int Maxn = 133015 ;
double ax[ Maxn] , ay[ Maxn] , bx[ Maxn] , by[ Maxn] ;
char sa[ Maxn/ 2 ] , sb[ Maxn/ 2 ] ;
int sum[ Maxn] ;
int x1[ Maxn] , x2[ Maxn] ;
int revv ( int x, int bits)
{
int ret = 0 ;
for ( int i = 0 ; i < bits; i++ )
{
ret <<= 1 ;
ret |= x & 1 ;
x >>= 1 ;
}
return ret;
}
void fft ( double * a, double * b, int n, bool rev)
{
int bits = 0 ;
while ( 1 << bits < n) ++ bits;
for ( int i = 0 ; i < n; i++ )
{
int j = revv ( i, bits) ;
if ( i < j)
swap ( a[ i] , a[ j] ) , swap ( b[ i] , b[ j] ) ;
}
for ( int len = 2 ; len <= n; len <<= 1 )
{
int half = len >> 1 ;
double wmx = cos ( 2 * PI / len) , wmy = sin ( 2 * PI / len) ;
if ( rev) wmy = - wmy;
for ( int i = 0 ; i < n; i += len)
{
double wx = 1 , wy = 0 ;
for ( int j = 0 ; j < half; j++ )
{
double cx = a[ i + j] , cy = b[ i + j] ;
double dx = a[ i + j + half] , dy = b[ i + j + half] ;
double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;
a[ i + j] = cx + ex, b[ i + j] = cy + ey;
a[ i + j + half] = cx - ex, b[ i + j + half] = cy - ey;
double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;
wx = wnx, wy = wny;
}
}
}
if ( rev)
{
for ( int i = 0 ; i < n; i++ )
a[ i] /= n, b[ i] /= n;
}
}
int solve ( int a[ ] , int na, int b[ ] , int nb, int ans[ ] )
{
int len = max ( na, nb) , ln;
for ( ln= 0 ; L ( ln) < len; ++ ln) ;
len= L ( ++ ln) ;
for ( int i = 0 ; i < len ; ++ i)
{
if ( i >= na) ax[ i] = 0 , ay[ i] = 0 ;
else ax[ i] = a[ i] , ay[ i] = 0 ;
}
fft ( ax, ay, len, 0 ) ;
for ( int i = 0 ; i < len; ++ i)
{
if ( i >= nb) bx[ i] = 0 , by[ i] = 0 ;
else bx[ i] = b[ i] , by[ i] = 0 ;
}
fft ( bx, by, len, 0 ) ;
for ( int i = 0 ; i < len; ++ i)
{
double cx = ax[ i] * bx[ i] - ay[ i] * by[ i] ;
double cy = ax[ i] * by[ i] + ay[ i] * bx[ i] ;
ax[ i] = cx, ay[ i] = cy;
}
fft ( ax, ay, len, 1 ) ;
for ( int i = 0 ; i < len; ++ i)
ans[ i] = ( int ) ( ax[ i] + 0.5 ) ;
return len;
}
string mul ( string sa, string sb)
{
int l1, l2, l;
int i;
string ans;
memset ( sum, 0 , sizeof ( sum) ) ;
l1 = sa. size ( ) ;
l2 = sb. size ( ) ;
for ( i = 0 ; i < l1; i++ )
x1[ i] = sa[ l1 - i - 1 ] - '0' ;
for ( i = 0 ; i < l2; i++ )
x2[ i] = sb[ l2- i- 1 ] - '0' ;
l = solve ( x1, l1, x2, l2, sum) ;
for ( i = 0 ; i< l || sum[ i] >= 10 ; i++ )
{
sum[ i + 1 ] += sum[ i] / 10 ;
sum[ i] %= 10 ;
}
l = i;
while ( sum[ l] <= 0 && l> 0 ) l-- ;
for ( i = l; i >= 0 ; i-- ) ans+= sum[ i] + '0' ;
return ans;
}
string Pow ( string a, int n)
{
if ( n== 1 ) return a;
if ( n& 1 ) return mul ( Pow ( a, n- 1 ) , a) ;
string ans= Pow ( a, n/ 2 ) ;
return mul ( ans, ans) ;
}
int main ( )
{
cin. sync_with_stdio ( false ) ;
string a;
int b;
while ( cin>> a>> b) cout<< Pow ( a, b) << endl;
return 0 ;
}
高精度GCD
算法思想:高精度加减乘除的运用。
算法复杂度:已无法估计。
# include <iostream>
# include <cstring>
# include <algorithm>
using namespace std;
const int L= 110 ;
string add ( string a, string b)
{
string ans;
int na[ L] = { 0 } , nb[ L] = { 0 } ;
int la= a. size ( ) , lb= b. size ( ) ;
for ( int i= 0 ; i< la; i++ ) na[ la- 1 - i] = a[ i] - '0' ;
for ( int i= 0 ; i< lb; i++ ) nb[ lb- 1 - i] = b[ i] - '0' ;
int lmax= la> lb? la: lb;
for ( int i= 0 ; i< lmax; i++ ) na[ i] += nb[ i] , na[ i+ 1 ] += na[ i] / 10 , na[ i] %= 10 ;
if ( na[ lmax] ) lmax++ ;
for ( int i= lmax- 1 ; i>= 0 ; i-- ) ans+= na[ i] + '0' ;
return ans;
}
string mul ( string a, string b)
{
string s;
int na[ L] , nb[ L] , nc[ L] , La= a. size ( ) , Lb= b. size ( ) ;
fill ( na, na+ L, 0 ) ; fill ( nb, nb+ L, 0 ) ; fill ( nc, nc+ L, 0 ) ;
for ( int i= La- 1 ; i>= 0 ; i-- ) na[ La- i] = a[ i] - '0' ;
for ( int i= Lb- 1 ; i>= 0 ; i-- ) nb[ Lb- i] = b[ i] - '0' ;
for ( int i= 1 ; i<= La; i++ )
for ( int j= 1 ; j<= Lb; j++ )
nc[ i+ j- 1 ] += na[ i] * nb[ j] ;
for ( int i= 1 ; i<= La+ Lb; i++ )
nc[ i+ 1 ] += nc[ i] / 10 , nc[ i] %= 10 ;
if ( nc[ La+ Lb] ) s+= nc[ La+ Lb] + '0' ;
for ( int i= La+ Lb- 1 ; i>= 1 ; i-- )
s+= nc[ i] + '0' ;
return s;
}
int sub ( int * a, int * b, int La, int Lb)
{
if ( La< Lb) return - 1 ;
if ( La== Lb)
{
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( a[ i] > b[ i] ) break ;
else if ( a[ i] < b[ i] ) return - 1 ;
}
for ( int i= 0 ; i< La; i++ )
{
a[ i] -= b[ i] ;
if ( a[ i] < 0 ) a[ i] += 10 , a[ i+ 1 ] -- ;
}
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( a[ i] ) return i+ 1 ;
return 0 ;
}
string div ( string n1, string n2, int nn)
{
string s, v;
int a[ L] , b[ L] , r[ L] , La= n1. size ( ) , Lb= n2. size ( ) , i, tp= La;
fill ( a, a+ L, 0 ) ; fill ( b, b+ L, 0 ) ; fill ( r, r+ L, 0 ) ;
for ( i= La- 1 ; i>= 0 ; i-- ) a[ La- 1 - i] = n1[ i] - '0' ;
for ( i= Lb- 1 ; i>= 0 ; i-- ) b[ Lb- 1 - i] = n2[ i] - '0' ;
if ( La< Lb || ( La== Lb && n1< n2) ) {
return n1; }
int t= La- Lb;
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( i>= t) b[ i] = b[ i- t] ;
else b[ i] = 0 ;
Lb= La;
for ( int j= 0 ; j<= t; j++ )
{
int temp;
while ( ( temp= sub ( a, b+ j, La, Lb- j) ) >= 0 )
{
La= temp;
r[ t- j] ++ ;
}
}
for ( i= 0 ; i< L- 10 ; i++ ) r[ i+ 1 ] += r[ i] / 10 , r[ i] %= 10 ;
while ( ! r[ i] ) i-- ;
while ( i>= 0 ) s+= r[ i-- ] + '0' ;
i= tp;
while ( ! a[ i] ) i-- ;
while ( i>= 0 ) v+= a[ i-- ] + '0' ;
if ( v. empty ( ) ) v= "0" ;
if ( nn== 1 ) return s;
if ( nn== 2 ) return v;
}
bool judge ( string s)
{
for ( int i= 0 ; i< s. size ( ) ; i++ )
if ( s[ i] != '0' ) return false ;
return true ;
}
string gcd ( string a, string b)
{
string t;
while ( ! judge ( b) )
{
t= a;
a= b;
b= div ( t, b, 2 ) ;
}
return a;
}
int main ( )
{
cin. sync_with_stdio ( false ) ;
string a, b;
while ( cin>> a>> b) cout<< gcd ( a, b) << endl;
return 0 ;
}
高精度进制转换
算法思想:模拟手工进制转换。
算法复杂度:o ( n^ 2 ) 。
# include <iostream>
# include <algorithm>
using namespace std;
bool judge ( string s)
{
for ( int i= 0 ; i< s. size ( ) ; i++ )
if ( s[ i] != '0' ) return 1 ;
return 0 ;
}
string solve ( string s, int n, int m)
{
string r, ans;
int d= 0 ;
if ( ! judge ( s) ) return "0" ;
while ( judge ( s) )
{
for ( int i= 0 ; i< s. size ( ) ; i++ )
{
r+= ( d* n+ s[ i] - '0' ) / m+ '0' ;
d= ( d* n+ ( s[ i] - '0' ) ) % m;
}
s= r;
r= "" ;
ans+= d+ '0' ;
d= 0 ;
}
reverse ( ans. begin ( ) , ans. end ( ) ) ;
return ans;
}
int main ( )
{
string s;
while ( cin>> s)
{
cout<< solve ( s, 10 , 7 ) << endl;
}
return 0 ;
}
高精度求平方根
思路就是二分+ 高精度加减乘除法
设数的长度为n,则需二分log ( 2 , 10 ^ n) 次即n* log ( 2 , 10 ) 约等于n* 3.3 ,由于数的长度为n,朴素高精度乘法复杂度为o ( n^ 2 ) 。故朴素算法求解高精度平方根复杂度为O ( n^ 3 )
当然,你也可以用FFT优化下高精度乘法。
下面的代码实现了求大整数平方根的整数部分。
JAVA版
import java. io. * ;
import java. math. * ;
import java. util. * ;
public class Main {
static Scanner cin = new Scanner ( new BufferedInputStream ( System. in) ) ;
public static BigInteger BigIntegerSqrt ( BigInteger n) {
BigInteger l= BigInteger. ONE, r= n, mid, ans= BigInteger. ONE;
while ( l. compareTo ( r) <= 0 ) {
mid= l. add ( r) . divide ( BigInteger. valueOf ( 2 ) ) ;
if ( mid. multiply ( mid) . compareTo ( n) <= 0 ) {
ans= mid;
l= mid. add ( BigInteger. ONE) ;
} else {
r= mid. subtract ( BigInteger. ONE) ;
}
}
return ans;
}
public static void main ( String args [ ] ) {
BigInteger n;
int t;
t= cin. nextInt ( ) ;
while ( t > 0 )
{
t-- ;
n= cin. nextBigInteger ( ) ;
BigInteger ans= BigIntegerSqrt ( n) ;
System. out. println ( ans) ;
}
}
}
C++ 版
# include <iostream>
# include <cstring>
# include <cstdio>
# include <algorithm>
using namespace std;
const int L= 2015 ;
string add ( string a, string b)
{
string ans;
int na[ L] = { 0 } , nb[ L] = { 0 } ;
int la= a. size ( ) , lb= b. size ( ) ;
for ( int i= 0 ; i< la; i++ ) na[ la- 1 - i] = a[ i] - '0' ;
for ( int i= 0 ; i< lb; i++ ) nb[ lb- 1 - i] = b[ i] - '0' ;
int lmax= la> lb? la: lb;
for ( int i= 0 ; i< lmax; i++ ) na[ i] += nb[ i] , na[ i+ 1 ] += na[ i] / 10 , na[ i] %= 10 ;
if ( na[ lmax] ) lmax++ ;
for ( int i= lmax- 1 ; i>= 0 ; i-- ) ans+= na[ i] + '0' ;
return ans;
}
string sub ( string a, string b)
{
string ans;
int na[ L] = { 0 } , nb[ L] = { 0 } ;
int la= a. size ( ) , lb= b. size ( ) ;
for ( int i= 0 ; i< la; i++ ) na[ la- 1 - i] = a[ i] - '0' ;
for ( int i= 0 ; i< lb; i++ ) nb[ lb- 1 - i] = b[ i] - '0' ;
int lmax= la> lb? la: lb;
for ( int i= 0 ; i< lmax; i++ )
{
na[ i] -= nb[ i] ;
if ( na[ i] < 0 ) na[ i] += 10 , na[ i+ 1 ] -- ;
}
while ( ! na[ -- lmax] && lmax> 0 ) ; lmax++ ;
for ( int i= lmax- 1 ; i>= 0 ; i-- ) ans+= na[ i] + '0' ;
return ans;
}
string mul ( string a, string b)
{
string s;
int na[ L] , nb[ L] , nc[ L] , La= a. size ( ) , Lb= b. size ( ) ;
fill ( na, na+ L, 0 ) ; fill ( nb, nb+ L, 0 ) ; fill ( nc, nc+ L, 0 ) ;
for ( int i= La- 1 ; i>= 0 ; i-- ) na[ La- i] = a[ i] - '0' ;
for ( int i= Lb- 1 ; i>= 0 ; i-- ) nb[ Lb- i] = b[ i] - '0' ;
for ( int i= 1 ; i<= La; i++ )
for ( int j= 1 ; j<= Lb; j++ )
nc[ i+ j- 1 ] += na[ i] * nb[ j] ;
for ( int i= 1 ; i<= La+ Lb; i++ )
nc[ i+ 1 ] += nc[ i] / 10 , nc[ i] %= 10 ;
if ( nc[ La+ Lb] ) s+= nc[ La+ Lb] + '0' ;
for ( int i= La+ Lb- 1 ; i>= 1 ; i-- )
s+= nc[ i] + '0' ;
return s;
}
int sub ( int * a, int * b, int La, int Lb)
{
if ( La< Lb) return - 1 ;
if ( La== Lb)
{
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( a[ i] > b[ i] ) break ;
else if ( a[ i] < b[ i] ) return - 1 ;
}
for ( int i= 0 ; i< La; i++ )
{
a[ i] -= b[ i] ;
if ( a[ i] < 0 ) a[ i] += 10 , a[ i+ 1 ] -- ;
}
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( a[ i] ) return i+ 1 ;
return 0 ;
}
string div ( string n1, string n2, int nn)
{
string s, v;
int a[ L] , b[ L] , r[ L] , La= n1. size ( ) , Lb= n2. size ( ) , i, tp= La;
fill ( a, a+ L, 0 ) ; fill ( b, b+ L, 0 ) ; fill ( r, r+ L, 0 ) ;
for ( i= La- 1 ; i>= 0 ; i-- ) a[ La- 1 - i] = n1[ i] - '0' ;
for ( i= Lb- 1 ; i>= 0 ; i-- ) b[ Lb- 1 - i] = n2[ i] - '0' ;
if ( La< Lb || ( La== Lb && n1< n2) ) {
return n1; }
int t= La- Lb;
for ( int i= La- 1 ; i>= 0 ; i-- )
if ( i>= t) b[ i] = b[ i- t] ;
else b[ i] = 0 ;
Lb= La;
for ( int j= 0 ; j<= t; j++ )
{
int temp;
while ( ( temp= sub ( a, b+ j, La, Lb- j) ) >= 0 )
{
La= temp;
r[ t- j] ++ ;
}
}
for ( i= 0 ; i< L- 10 ; i++ ) r[ i+ 1 ] += r[ i] / 10 , r[ i] %= 10 ;
while ( ! r[ i] ) i-- ;
while ( i>= 0 ) s+= r[ i-- ] + '0' ;
i= tp;
while ( ! a[ i] ) i-- ;
while ( i>= 0 ) v+= a[ i-- ] + '0' ;
if ( v. empty ( ) ) v= "0" ;
if ( nn== 1 ) return s;
if ( nn== 2 ) return v;
}
bool cmp ( string a, string b)
{
if ( a. size ( ) < b. size ( ) ) return 1 ;
if ( a. size ( ) == b. size ( ) && a<= b) return 1 ;
return 0 ;
}
string BigInterSqrt ( string n)
{
string l= "1" , r= n, mid, ans;
while ( cmp ( l, r) )
{
mid= div ( add ( l, r) , "2" , 1 ) ;
if ( cmp ( mul ( mid, mid) , n) ) ans= mid, l= add ( mid, "1" ) ;
else r= sub ( mid, "1" ) ;
}
return ans;
}
string DeletePreZero ( string s)
{
int i;
for ( i= 0 ; i< s. size ( ) ; i++ )
if ( s[ i] != '0' ) break ;
return s. substr ( i) ;
}
int main ( )
{
string n;
int t;
cin>> t;
while ( t-- )
{
cin>> n;
n= DeletePreZero ( n) ;
cout<< BigInterSqrt ( n) << endl;
}
return 0 ;
}