题目一
生成元
题目内容
如果x加上x的各个数之和得到y,就说x是y的生成元。给出n(1=<n<=100000),求最小生成元。无解输出0。
样例输入
216
121
2005
样例输出
198
0
1979
解题思路
假设用枚举方式,在给出n后依次计算0~n-1 范围内所有数,这样可以找到答案不过效率上不高。由于每次输出都要计算0~n-1中大部分数,无解时甚至要计算所有数才能得到答案。因此不妨直接把0 ~100000所有数先直接计算,并标记给对应的数字表示该数是对应的最小生成元,最后输出数字对应的标记即可。
- 首先我们以数组来记录每个序列数对应的生成元,初始化为0
- 当数字x计算得到y时,将x的值赋予a[y]来表示y对应的生成元为x
- 最后输出即可
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100005;
int a[N];
int main()
{
int n,m,t;
memset(a,0,sizeof(a));
for(int m=1;m<N;m++)
{
//y为本身,x用于给出本身各个数之和
int x=m,y=m;
//循环计算该生成元对应数
while(x){ y+=x %10; x/=10;}
//更新最小生成元
if(a[y]==0 || m<a[y]) a[y]=m;
}
while(scanf("%d",&n)!=EOF && n)
{
printf("%d\n",a[n]);
}
return 0;
}
题目二
环状序列
题目内容
输入一个长度为n(n=<100)的环状DNA串(只包含 A、C、G、T这四种字符)的一种表示法,任务时输出该环状串的最小表示。
样例输入
CGAGTCAGCT
CTCC
样例输出
AGCTCGAGTC
CCCT
解题思路
该题有字典序就可解决,只需要判断每个节点开始的序列 中对应位置字符的大小即可。即数组中下标为0开始的序列和为1开始的序列中一一对应的字符大小。
- 编写一个判断函数,设置一个答案节点即下标和一个用来比较的节点。
- 主函数中输入环状串,用for循环去改变比较节点,然后带入函数去判断,若该序列的字典序小会返回1,以此用if去判断是否成立,并在成立后更新answer为比较节点。
#include <cstring>
#include<cstdio>
using namespace std;
const int N=105;
int smallest(const char*s, int p, int q)
{
int len=strlen(s);
for(int i=0;i<len;i++)
{
//先判断是否相等,再判断当前字典序是否小于原答案
if(s[(p+i)%len] != s[(q+i)%len])
return s[(p+i)%len] < s[(q+i)%len];
//也可以直接判断当前字典序小于原答案时return 1表示正确
}
return 0;
}
int main()
{
int t;
char s[N];
scanf("%d",&t);
while(t--)
{
scanf("%s",s);
int ans = 0;
int n = strlen(s);
//ans从0开始所以i从1开始比较
for(int i=1;i<n;i++)
//若i起头的字典序小更新ans
if(smallest(s,i,ans)) ans=i;
for(int i=0;i<n;i++)
putchar(s[(ans+i)%n]);
putchar('\n');
}
return 0;
}
/*代码参考于算法竞赛入门经典第二版,作者 刘汝佳