ZOJ 2646 Joseph's Problem

本文介绍了一种高效的算法设计方法,用于解决大规模数据集上的特定数学问题。通过对数据进行分组并利用等差数列的特性来减少计算量,该算法能够在合理的时间内处理十亿级别的数据。文中提供了一个C++实现的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给出K和N,求 ,N,K < 109

数据如此BT,从1到N穷举是不可能的。不妨列出小规模时的情况。比如N = 5,K = 5。

5%5=0  5/5=1

5%4=1  5/4=1

5%3=2  5/3=1

5%2=1  5/2=2

5%1=0  5/1=5

可以看到当商相同时,余数成等差数列,这是题目的关键。所以我们可以穷举商,计算等差数列之和。

 

#include <cstdio>
#include 
<string>

int N, K, l[20];

void proc ();

int main ()
{
    
//freopen ( "in.txt", "r", stdin );
    while ( scanf ( "%d%d"&N, &K ) == 2 )
    
{
        proc ();
    }

    
return 0;
}


void addm ( int a[], int x, int y )
{
    
int i, j;        // 这题数据太bt,高精度乘法= = 
    int lx[10], ly[10],
        sx, sy;        
// 长度
    for ( i = 0; i < 10; i ++, x /= 10 )
    
{
        lx[i] 
= x % 10;
        
if ( x == 0 )
        
{
            sx 
= i;
            
break;
        }

    }

    
for ( j = 0; j < 10; j ++, y /= 10 )
    
{
        ly[j] 
= y % 10;
        
if ( y == 0 )
        
{
            sy 
= j;
            
break;
        }

    }

    
for ( i = 0; i < sx; i ++ )
    
{
        
for ( j = 0; j < sy; j ++ )
        
{
            a[i 
+ j] += lx[i] * ly[j];
        }

    }

    
int c = 0, t;
    
for ( i = 0; i < 20; i ++ )
    
{
        t 
= a[i] + c;
        a[i] 
= t % 10, c = t / 10;
    }

}


void print ( int a[] )
{
    
int i;
    
for ( i = 20; i >= 0; i -- )
        
if ( a[i] )
            
break;
    
if ( i == -1 )
    
{
        printf ( 
"0 " );
        
return;
    }

    
for ( ; i >= 0; i -- )
        printf ( 
"%d", a[i] );
    printf ( 
" " );
}


void proc ()
{
    
int d;    // 商 
    memset ( l, 0x00sizeof ( l ) );
    
int L = 0;
    
if ( N < 10000 )
    
{
        
for ( d = 1; d <= N; d ++ )
            L 
+= K % d;
        printf ( 
"%d ", L );
        
return;
    }

    
// z = k / i
    if ( K < N ) 
        d 
= 1;
    
else 
        d 
= K / N;
    
int low, high, first = 1;
    
for ( ; d * d <= K; d ++ )
    
{
        high 
= K / d, low = K / ( d + 1 ) + 1;
        
if ( N < K && first )
            high 
= N, first = 0;
        
int x = high - low + 1;
        low 
= K % low; 
        high 
= K % high;
        
int y = high + low;
        
//sum += double ( x ) * double ( high + low ) / 2;
        if ( x % 2 == 0 )
            x 
/= 2;
        
else
            y 
/= 2;
        addm ( l, x, y );
    }

    
//printf ( "%.0f ", sum );
    low = K / d;
    
for ( ; low >= 2; low -- )
        
//sum += K % low;
        addm ( l, K % low, 1 );
    
if ( K < N )
        
//sum += double ( K ) * double ( N - K );
        addm ( l, K, N - K );
    print ( l );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值