随笔 - 68  文章 - 57  trackbacks - 0
<2024年7月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用链接

留言簿(8)

随笔分类(74)

随笔档案(68)

搜索

  •  

最新评论

阅读排行榜

评论排行榜

比较赤裸的模线性方程组模型了,给定的模都是两两互素的,可以用扩展欧几里德和孙子定理来解。第一次写这个,不知道健壮性如何,这个题目数据貌似很弱。。
TJU 3027
posted @ 2009-03-22 09:51 sdfond 阅读(234) | 评论 (0)编辑 收藏
基本的判素都比较慢,对于这个题目的BT数据量(2 ^ 31),也只能用概率判素模型了。
Miller-Rabin基于费马小定理:如果(a, p) = 1,那么a ^ (p - 1) = 1 mod p。满足这个性质的p叫伪素数,如果一个数是伪素数,那么它有很大可能是素数。通过多次的枚举a,利用快速幂取模判断,就可以知道p是不是素数,Miller-Rabin测试的成功率在3/4。
费马小定理是该定理的特殊形式:如果p是素数,那么对于任意整数a:a ^ p = a mod p。这个定理可以用归纳法证明,证明依据这样一个事实:组合数C(n, k)是一个整数,如果n是素数,那么n和k!、(n - k)!的每一项都互素,可以提出n,也就是C(n, k) / n也是整数,所以n | C(n, k)。
这个题目的代码如下:
#include <cstdio>
#include 
<stdlib.h>
const int MAX = 4, N = 1000000;

long long PowerMod(long long a, long long b, long long k)
{
    
long long ret = 1, f = a;

    
while (b)
    
{
        
if (b & 1)
            ret 
= ret * f % k;
        f 
= f * f % k;
        b 
>>= 1;
    }

    
return ret;
}

bool MillerRabin(long long n)
{
    
int i;
    
long long tmp;

    srand(
100);
    
for (i = 0; i < MAX; i++)
    
{
        tmp 
= rand() % (n - 1+ 1;
        
if (PowerMod(tmp, n - 1, n) != 1)
            
break;
    }

    
return (i == MAX);
}


int main()
{
    
long long n, i, j;
    
bool tag[N] = {110};

    
for (i = 2; i * i < N; i++)
    
{
        
if (tag[i]) continue;
        
for (j = i; j * i < N; j++)
            tag[j
*i] = 1;
    }

    
while (scanf("%lld"&n) == 1)
    
{
        
if (n < N)
            printf(
"%s\n", tag[n] ? "NO" : "YES");
        
else
            printf(
"%s\n", ((n & 1== 0|| !MillerRabin(n) ? "NO" : "YES");
    }


    
return 0;
}

posted @ 2009-03-18 21:15 sdfond 阅读(600) | 评论 (0)编辑 收藏

也是很赤裸裸的模型,这里求的是绝对值最小解,还有就是用到高精。我用java不会写传引用,因此只好开了全局变量。

import java.math.*;
import java.util.*;

public class Main
{
  
static public BigInteger x = null, y = null;
    
  
static BigInteger extended_gcd(BigInteger a, BigInteger b)
  
{
      BigInteger zero 
= new BigInteger(new String("0"));
      BigInteger ret, tmp;
      
      
if (b.compareTo(zero) == 0)
      
{
          x 
= new BigInteger(new String("1"));
          y 
= zero;
          
return a;
      }

      ret 
= extended_gcd(b, a.mod(b));
      tmp 
= x;
      x 
= y;
      y 
= tmp.subtract(a.divide(b).multiply(y));
      
      
return ret;
  }

  
  
static BigInteger modular_linear_equation(BigInteger a, BigInteger b, BigInteger n)
  
{
      BigInteger e, e2;
      BigInteger d 
= extended_gcd(a, n);
      e 
= b.divide(d).multiply(x).mod(n.divide(d));
      e2 
= e.subtract(n.divide(d)).abs();
      
      
if (e.compareTo(e2) < 0)    return e;
      
return e2;
  }

  
  
public static void main(String[] args)
  
{
      BigInteger a, b, c;
      Scanner in 
= new Scanner(System.in);
    
      
while (in.hasNext())
      
{
          a 
= in.nextBigInteger();
          b 
= in.nextBigInteger();
          c 
= in.nextBigInteger();
          c 
= c.multiply(new BigInteger(new String("-1")));
          System.out.println(modular_linear_equation(a, c, b));
      }

  }

}
posted @ 2009-03-17 20:16 sdfond 阅读(150) | 评论 (0)编辑 收藏
最后化成c * x = b - a mod (2 ^ k),解这个模线性方程,输出最小正解即可。
写程序的时候有了一个误区,以为如果b - a是负的,把它化成正的话那么输出的时候就可以直接模2 ^ k,不用再考虑是负的情况了。但是忽略了x可能为负的情况,所以WA了很多次。其实根本不需考虑b - a的正负性,最后输出的时候加2 ^ k再模2 ^ k就行了。
还有一个是输出最小解,因为最后的所有解模n / d同余,因此直接模n / d即可。
#include <cstdio>

//ax + by = gcd(a, b)
long long extended_gcd(long long a, long long b, long long &x, long long &y)
{
    
long long ret, tmp;
    
if (!b)
    
{
        x 
= 1, y = 0;
        
return a;
    }

    ret 
= extended_gcd(b, a % b, x, y);
    tmp 
= x;
    x 
= y;
    y 
= tmp - a / b * y;
    
return ret;
}


//ax = b mod n
long long modular_linear_equation(long long a, long long b, long long n)
{
    
long long x, y, e;
    
long long d = extended_gcd(a, n, x, y);
    
if (b % d)  return -1;
    e 
= b / d * x % n + n;
    
return e % (n / d);
}


int main()
{
    
long long a, b, c, ans;
    
int k;

    
while (scanf("%lld %lld %lld %d"&a, &b, &c, &k) == 4)
    
{
        
if (a == 0 && b == 0 && c == 0 && k == 0)
            
break;
        ans 
= modular_linear_equation(c, b - a, 1LL << k);
        
if (ans == -1)
            puts(
"FOREVER");
        
else
            printf(
"%lld\n", ans);
    }


    
return 0;
}

posted @ 2009-03-17 18:53 sdfond 阅读(1491) | 评论 (2)编辑 收藏
这个是经典的Eraosthenes筛法:
for (int i = 2; i * i < N; i++)
{
    
if (tag[i]) continue;
    
for (int j = i; i * j < N; j++)
        tag[i
*j] = 1;
}
for (int i = 2; i < N; i++)
    
if (!tag[i])
        prime[tol
++= i;

但是Eraosthenes筛法的速度并不快,原因在于对于一个合数,这种方法会重复的标记。一种线性筛素数的方法有效的解决了这一点,代码如下:
void get_prime()
{
    
int cnt = 0;
    
for (int i = 2; i < N; i++)
    {
        
if (!tag[i])    p[cnt++= i;
        
for (int j = 0; j < cnt && p[j] * i < N; j++)
        {
            tag[i
*p[j]] = 1;
            
if (i % p[j] == 0)
                
break;
        }
    }
}
可以用均摊分析的方法来分析这个算法的复杂度:由于每个合数都唯一的被它的最小素因子筛一次,而每个合数的最小素因子都是唯一的,因此总复杂度是O(n)。
这种筛法的思想很强悍,有很多利用价值,可以根据这种方法做到线性筛欧拉函数等等,继续研究中。。
posted @ 2009-03-16 21:29 sdfond 阅读(4590) | 评论 (5)编辑 收藏
仅列出标题
共14页: First 6 7 8 9 10 11 12 13 14