SDUT 2165 山东省第二届ACM省赛 Crack Mathmen (逆向思维)

传送门:SDUT 2165



题目大意:

对于每一个英文字符和数字,我们按照以下加密原则加密:(字符的ASCII码值)^n mod 997 = y,得到三位数的 y(如果不满三位则补0)。


现在给你 n 和 y 的值,让你求加密之前的明文是什么。如果明文不存在或者不唯一则输出 No Solution。



思路:

如果给定 n、y,让求 x^n mod 997 = y,中的 x 的值是很难求的。所以我们可以换个角度思考。


y值的来源只可能是大小写字母和数字字符加密后得到的,并且应该一一对应,而这些字符的个数有限,所以我们可以先通过快速幂得到每个字符对应的密文值。然后对于截获的密文中的每一个值去找它对应的字符,如果不存在或者存在多个则无解。


因为要按照密文值找加密前的字符,所以我用的 vector数组存储的每个密文值对应的密文可能是什么。



代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
using namespace std;

char s[1000010],ans[400010];

int q_mod(int a,int b,int m)
{ //快速幂取模 
	int base=a,r=1;
	while(b)
	{
		if(b&1) r=(r*base)%m;
		base=(base*base)%m;		
		b>>=1;
	}
	return r;
}

int main()
{	
	int i,t,n,a,f,rlt,len,tol;	
	vector<char> vct[1000]; //记录每个密文值对应的密文 
	scanf("%d",&t);	
	while(t--)
	{
		scanf("%d%s",&n,s);
		for(i=0;i<1000;i++) vct[i].clear();
		for(i='a';i<='z';i++)
		{ //计算 a~z 对应的密文值 
			rlt=q_mod(i,n,997);
			vct[rlt].push_back((char)i);
		}
		for(i='A';i<='Z';i++)
		{ //计算 A~Z 对应的密文值
			rlt=q_mod(i,n,997);
			vct[rlt].push_back((char)i);
		}
		for(i='0';i<='9';i++)
		{ //计算 0~9 对应的密文值
			rlt=q_mod(i,n,997);
			vct[rlt].push_back((char)i);
		}		
		f=1;
		tol=0;
		len=strlen(s);		
		for(i=0;i<len;i+=3)
		{
			a=(s[i]-'0')*100+(s[i+1]-'0')*10+(s[i+2]-'0');
			if(vct[a].size()>1||vct[a].size()==0)
			{ //如果密文不存在或存在多个 
				f=0;
				break;
			}
			else ans[tol++]=vct[a][0]; //记录结果 
		}		
		if(!f) printf("No Solution\n");
		else
		{
			for(i=0;i<tol;i++) printf("%c",ans[i]);
			printf("\n");
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zuzhiang/article/details/79907705