【kAriOJ】离散数学春季学期编程测试 1

2020-06-02 15:35:14 浏览数 (1)

A。凯撒密码

题意:

给你k1,k2,和一串明文,一串密文。

明文用k1加密,密文用k2解密。

对于明文要把字母转换成大写字母,非字母全部删除。

额:要考虑到取模可能会变成负数,所以要加一下26再取模。

代码:

代码语言:javascript复制
#include<stdio.h>
#define N 85
int k1, k2;
char plain[N], cipher[N];
void init(char s[]) //预处理,转换为大写字母
{
    int i;
    for(i = 0; s[i]; i  )
        if(s[i] >= 'a' && s[i] <= 'z')
            s[i] = s[i] - 'a'   'A';
}
void encrypt(char s[],int k,int f)//加解密
{
    init(s);
    int i;
    for(i = 0; s[i]; i  )
        if(s[i] >= 'A' && s[i] <= 'Z')
            printf("%c", ((s[i] - 'A'   k*f   26) % 26    'A'));
    printf("n");
}
int main()
{
    scanf("%d,%d ", &k1, &k2);
    gets(plain);
    gets(cipher);
    encrypt(plain,k1,1);
    encrypt(cipher,k2,-1);
    return 0;
}

B。RSA加密 

题意:

给你n,e,和一串明文。用(n,e)加密明文。将明文字母转换成数字,按8位数字分段,不足部分补足0。明文中有非字母删除,A和a转成数字都是00, Z和z转成数字都是25。明文数字8位分段的每一段对应的密文也要求是8位,如果不足8位,前面补足0。

对于明文要把字母转换成大写字母,非字母全部删除。

补充:

RSA加密就是字母转化为两位数字,分段处理,比如每八个一段,M为明文数字段,C为密文数字段,C=Me%n。

代码:

代码语言:javascript复制
#include<stdio.h>
#include<string.h>
#define N 1000
#define ll long long
ll n, e;
char plain[N];
ll qpow(ll a, ll b)//快速幂
{
    ll k = a % n;
    ll ans = 1;
    while(b)
    {
        if(b & 1)
            ans = (ans * k ) % n;
        k = ( k * k) % n;
        b >>= 1;
    }
    return ans;
}
void init(char s[]) //预处理,转换为大写字母
{
    int i;
    for(i = 0; s[i]; i  )
        if(s[i] >= 'a' && s[i] <= 'z')
            s[i] = s[i] - 'a'   'A';
}
void encrypt(char s[]) //加密
{
    init(s);
    int k = 0,i;
    ll block = 0;
    for(i = 0; s[i]; i  )
        if(s[i] >= 'A' && s[i] <= 'Z') //如果是字母
        {
            block = block * 100   (s[i] - 'A') ; //明文对应的数字串
            k  ;
            if(k == 4) //够8位数字时
            {
                printf("lld", qpow(block, e) % 100000000);//输出密文,这个模不知道是不是必须的,题目没说n的上限
                block = 0;
                k = 0;
            }
        }
    if(k)//剩下的明文要后面补零
    {
        while(k != 4)
        {
            block = block * 100;
            k  ;
        }
        printf("lld", qpow(block, e) % 100000000);
    }
}
int main()
{
    //  freopen("in.txt", "r", stdin);
    scanf("%lld%lld ", &n, &e);
    gets(plain);
    encrypt(plain);
    return 0;
}

C。RSA解密 

题意:

给你n,e,和一串明文。用(n,e)加密明文。将明文字母转换成数字,按8位数字分段,不足部分补足0。明文中有非字母删除,A和a转成数字都是00, Z和z转成数字都是25。明文数字8位分段的每一段对应的密文也要求是8位,如果不足8位,前面补足0。

对于明文要把字母转换成大写字母,非字母全部删除。

补充:

RSA加密就是字母转化为两位数字,分段处理,比如每八个一段,M为明文数字段,C为密文数字段,C=Me%n。

代码:

代码语言:javascript复制
#include<stdio.h>
#include<string.h>
#define N 802
#define ll long long
ll n, e, p, q, d, x, y;
char cipher[N << 1], plain[10];
ll exgcd(ll a, ll b)//扩展欧几里德求逆元
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll r = exgcd(b, a % b);
    ll tmp = x;
    x = y;
    y = tmp - a / b * y;
    return r;
}
ll qpow(ll a, ll b)//快速幂
{
    ll k = a % n;
    ll ans = 1;
    while(b)
    {
        if(b & 1)
            ans = (ans * k ) % n;
        k = ( k * k) % n;
        b >>= 1;
    }
    return ans;
}
void init()//求p和q,和d
{
    int i;
    for(i = 2; i < n; i  )
        if(n % i == 0)
        {
            p = i;
            q = n / i;
            break;
        }
    ll M;
    M = (p - 1) * (q - 1);
    exgcd(e, M);
    d = (x % M   M) % M;//求e的逆元d
}
void decrypt() //解密
{
    ll block = 0;
    int k = 0, i, j;
    for(i = 0; cipher[i]; i  )
    {
        block = block * 10   cipher[i] - '0';//密文从字符串中取出来
        k  ;
        if(k == 8)//密文达到8位数字时
        {
            memset(plain, 0, sizeof plain);//清空明文字符串
            block = qpow(block, d);//计算明文数字串
            for(j = 3; j >= 0; j--)//每次计算两位数字并存在明文字符串中,因为从后面往前取,所以倒过来存
            {
                plain[j] = block % 100   'A';//取最后面两个数字
                block /= 100;//去掉最后面两个数字
            }
            printf("%s", plain);//输出明文
            k = 0;//清空计数器
        }
    }
}
int main()
{
    //  freopen("in.txt", "r", stdin);
    scanf("%lld%lld ", &n, &e);
    gets(cipher);
    init();
    printf("%dn", d);
    decrypt();
    return 0;
}

0 人点赞