Codevs P1982 加密算法

10 篇文章 0 订阅
4 篇文章 0 订阅

Codevs P1982 加密算法

 

题目描述 Description

Rivest是密码学专家。近日他正在研究一种数列E={E[1],E[2],……,E[n]},
且E[1]=E[2]=p(p为一个质数),E[i]=E[i-2]*E[i-1] (若2<i<=n)。
例如{2,2,4,8,32,256,8192,……}就是p=2的数列。在此基础上他又设计了一种加密
算法,该算法可以通过一个密钥q (q<p)将一个正整数n加密成另外一个正整数d,计
算公式为:d=E[n] mod q。现在Rivest想对一组数据进行加密,但他对程序设计不太
感兴趣,请你帮助他设计一个数据加密程序。

输入描述 Input Description

读入m,p。其中m表示数据个数,p用来生成数列E。
以下有m行,每行有2个整数n,q。n为待加密数据,q为密钥。
规模:0<p,n<2^31;0<q<p;0<m<=5000。

输出描述 Output Description

将加密后的数据按顺序输出到文件a.out。
第i行输出第i个加密后的数据。

样例输入 Sample Input

2 7
4 5
4 6

样例输出 Sample Output

3
1

数据范围及提示 Data Size & Hint

 

分析

该题极度恶心,感觉在卡pascal,c++党开读入优化各种常数优化卡过去了。。。而P党悲催了,怎么都过不去。。。

 

首先,有题目中的E[i]:=E[i-1]*E[i-2]  再加上底数相等可以推知指数是Fibonacci数列的第n项,然后就可以通过矩阵乘法来加速转移。

然后由于指数仍旧很大,通过高次幂取模的降幂公式来将次方降到可以承受的地步,再快速幂即可完成该题,,,

pascal被卡。。。。。。。。。。( ˇˍˇ ),郁闷怎么也过不去。最好卡过去1个,还剩两个超时。。。

代码如下

{$inline on}
program encrypt;
type matrix=array[1..2,1..2] of qword;
var m,p,n,q,px,ans:qword;
    i:longint;
    euler:longint;
    c,t,f:matrix;
function _euler(x:longint):longint;inline;
var ans,n:longint;
    i:longint;
begin
 ans:=x;
 n:=x;
 i:=2;
 while i*i<=x do
  begin
   if x mod i=0
    then
     begin
      ans:=(ans div i)*(i-1);
      while x mod i=0 do
       x:=x div i;
     end;
   i:=i+1;
  end;
 if x>1 then ans:=(ans div x)*(x-1);
 exit(ans);
end;

function _matrix(a,b:matrix;n,m,k:longint):matrix;inline;
var i,j,p:longint;
begin
 fillchar(c,sizeof(c),0);
 for i:=1 to n do
  for j:=1 to m do
   for p:=1 to k do
    begin
     c[i,j]:=(c[i,j]+((a[i,p] mod euler)*(b[p,j] mod euler)) mod euler) mod euler;
    end;
 exit(c);
end;

function power(a:matrix;b:longint):matrix;inline;
var sum:matrix;
begin
 sum:=a;
 b:=b-1;
 while b<>0 do
  begin
   if b and 1=1 then sum:=_matrix(sum,a,2,2,2);
   b:=b>>1;
   a:=_matrix(a,a,2,2,2);
  end;
 exit(sum);
end;

function power2(a,b:qword):qword;inline;
var sum:qword;
begin
 sum:=1;
 while b<>0 do
  begin
   if b and 1=1 then sum:=(sum*a) mod q;
   b:=b>>1;
   a:=((a mod q)*(a mod q))mod q;
  end;
 exit(sum);
end;

begin
 readln(m,px);
 for i:=1 to m do
  begin
   readln(n,q);
   euler:=_euler(q);
   f[1,1]:=1; f[1,2]:=1;
   t[1,1]:=0; t[1,2]:=1;
   t[2,1]:=1; t[2,2]:=1;
   case n of
    1:begin n:=f[1,1] end;
    2:begin n:=f[1,2] end
 else begin
       t:=power(t,n-2);
       f:=_matrix(f,t,1,2,2);
       n:=f[1,2] mod euler;
      end
   end;
   ans:=power2(px,n);
   writeln(ans mod q);
  end;
end.

—————————————————♪(^∇^*)我是分割线╮(╯▽╰)╭——————————————————————————

评测结果

 

试点#a01.in 结果:AC 内存使用量: 128kB 时间使用量: 1ms 
测试点#a02.in 结果:AC 内存使用量: 256kB 时间使用量: 1ms 
测试点#a03.in 结果:AC 内存使用量: 128kB 时间使用量: 1ms 
测试点#a04.in 结果:AC 内存使用量: 256kB 时间使用量: 0ms 
测试点#a05.in 结果:AC 内存使用量: 256kB 时间使用量: 4ms 
测试点#a06.in 结果:AC 内存使用量: 128kB 时间使用量: 7ms 
测试点#a07.in 结果:AC 内存使用量: 128kB 时间使用量: 1ms 
测试点#a08.in 结果:AC 内存使用量: 256kB 时间使用量: 16ms 
测试点#a09.in 结果:AC 内存使用量: 256kB 时间使用量: 0ms 
测试点#a1.in 结果:AC 内存使用量: 256kB 时间使用量: 0ms 
测试点#a10.in 结果:AC 内存使用量: 256kB 时间使用量: 3ms 
测试点#a11.in 结果:AC 内存使用量: 256kB 时间使用量: 61ms 
测试点#a12.in 结果:AC 内存使用量: 256kB 时间使用量: 144ms 
测试点#a13.in 结果:AC 内存使用量: 256kB 时间使用量: 294ms 
测试点#a14.in 结果:AC 内存使用量: 256kB 时间使用量: 716ms 
测试点#a15.in 结果:AC 内存使用量: 256kB 时间使用量: 1074ms 
测试点#a16.in 结果:AC 内存使用量: 256kB 时间使用量: 1231ms 
测试点#a17.in 结果:AC 内存使用量: 256kB 时间使用量: 1156ms 
测试点#a18.in 结果:TLE 内存使用量: 236kB 时间使用量: 2000ms 
测试点#a19.in 结果:TLE 内存使用量: 256kB 时间使用量: 2000ms 
测试点#a2.in 结果:AC 内存使用量: 256kB 时间使用量: 1ms 
测试点#a20.in 结果:AC 内存使用量: 364kB 时间使用量: 1917ms 
测试点#a3.in 结果:AC 内存使用量: 256kB 时间使用量: 0ms 

————————————————————————————————————————————————————————————————————————————————

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值