输入一个占32 3232比特位的十进制正整数,按下述规则输出加密后的十进制整数:
设这个整数的二进制表示为
x x x x p p p p x x x x e e e e x x x x e e e e x x x x e e e e
,将其中标记为eeee的均左移8位,标记为pppp的右移24位,标记为xxxx的位置不变,输出加密后的数的十进制表示
Sample Input:
1234
Sample Output:
262864
题解:将x, p, e分解出来,然后再分别将p左移,e右移之后再加上x。
#include
int main()
{
long long n;
while(scanf("%lld", &n) != EOF)
{
long long e = n & (0x000f0f0f);
long long p = n & (0x0f000000);
long long x = n-e-p;
long long res = (e << 8) + (p >> 24) + x;
printf("%lld", res);
}
}
<< x表示对二进制数左移x位, >> x表示右移x位(均为逻辑移位)
&表示与, |表示或, ~表示取反, ^表示异或
这些运算符均可后面直接加整型数字
输入两个整数a和n,要求从a中删除n个位置上的数后剩下的数按原来的相对顺序组成的新数最小,求这个数
Sample Input:
62354 2
Sample Output:
234
解题思路:先定义一个结构体来存放a中每个位置上的字符已经该字符的位置,然后对字符进行排序,这样字符中最大的n个数字就会排在末尾,截取前面的部分(相当于删除了n个最大数字),再对前面几个数字根据刚开始记录的位置进行排序,这样前面的数字就能回归原来的顺序。
#include
#include
#include
#include
using namespace std;
struct f{
char c;
int pos;
}s[10];
bool cmp1(f a, f b)
{
return a.c < b.c;
}
bool cmp2(f a, f b)
{
return a.pos < b.pos;
}
int main()
{
string a;
int n;
while(cin >> a >> n)
{
for(int i = 0; i < a.length(); i++)
{
s[i].c = a[i];
s[i].pos = i;
}
sort(s, s+a.length(), cmp1);
sort(s, s+a.length()-n, cmp2);
for(int j = 0; j < a.length()-n; j++)
printf("%c", s[j].c);
printf("\n");
}
}
这个解法昨晚睡觉时想起来发现时错的,例如96328,去掉两位,按这个做法时632,但最小应该是328。
所以看了别人的解题思路华科2021机试:
96328去除两位还剩3位。设去除后的结果为result,则result第一位在963中选择(即【1,3】中选),不然会导致接下来的数字不够再选两位,而剩下两位只能从位置4开始选。
所以
转自上文链接
#include
#include
#include
using namespace std;
char s[1005];
int min_pos[1005][1005]; // min_pos[i][j]表示区间[i,j]的最小数的位置,如果有多个最小数,那么取最左边的那个数
int main() {
int m,n;
while(~scanf("%s %d",s+1,&m)) {//从s[1]开始存储
n = strlen(s+1);
for(int i=1;i<=n;i++) {
min_pos[i][i] = i;
for(int j=i+1;j<=n;j++) {
min_pos[i][j] = s[j] < s[min_pos[i][j-1]] ? j : min_pos[i][j-1];//依次找每个范围内的最小值的位置,用到了动态规划
}
}
int pre_pos = 0;
for(int i=1;i<=n-m;i++) printf("%c",s[pre_pos = min_pos[pre_pos+1][m+i]]);//pre_pos表示上一个最小数字的位置,下一个数字从pre_pos下一个来找
printf("\n");
}
}
bool judge(int x)
{
if(x <= 1) return false;
for(int i = 2; i*i <= x; i++)
if(x % i == 0)
return false;
return true;
}
题目:1.关于质数的问题:若x为质数,且2^x-1也为质数,则称x为梅森数,例如:3为质数,2 ^3-1=7也为质数,所以3满足条件,再如11是质数,但2 ^11-1=2047不是质数,所以11不满足条件;题目要求输入一个整数m,求出小于m满足条件的吗,梅森数,例如:
输入:97
输出:
M(2)=3
M(3)=7
M(5)=31
#include
#include
bool judge(int x)
{
if(x <= 1) return false;
for(int i = 2; i*i <= x; i++)
if(x % i == 0)
return false;
return true;
}
int main()
{
int n;
while(~scanf("%d", &n))
{
for(int i = 2; i < n; i++)//ksdhflkdsghldfglksgd
{
int res = (int)pow(2.0, double(i))-1;/*erskghrlktghlrtgnklddfbsgf
dhsfthhfdtrh
rthtyhty*/
if(res < n && judge(i) && judge(res))
printf("M(%d)=%d\n", i, res);
}
}
}
打开第一题的代码源文件.c/ .cpp要求原文件里含有//和/ * XXXXXX * /,输出该文件,共有三小问:
1.给每行代码加上序号,表明这是第几行
2.对于//字符不予输出//及该行之后的文本
3.同上,要求不要输出/ * * /及其之内的文本
解题思路:对原文件一行一行的读取,然后每一行一个字符一个字符的检测,如果出现//,那么忽略后面的内容,直接换行;如果出现/* */一般这类的注释都会有好几行,这个时候当遇到/ * 时对zs变量设置为1,表示现在遇到了多行注释,当遇到 * /时表示整行注释已经结束,设置zs为0。在一个字符一个字符的检查过程中若zs=0且没有遇到//或/ *则输出字符。
#include
#include
int main()
{
FILE * fp = fopen("2019-1.cpp", "r");
char s[100], ch;
int cnt = 1, zs = 0;
while(fgets(s, 200, fp) != NULL)
{
int len = strlen(s);
if(zs == 0)
printf("%d ", cnt++);
for(int i = 0; i < len; i++)
{
if(s[i] == '/')
{
if(i+1 < len && s[i+1] == '/')
{
printf("\n");
break;
}
else if(i+1 < len && s[i+1] == '*')
{
zs = 1;
break;
}
else if(zs == 0)
printf("%c", s[i]);
}
else if(s[i] == '*' && i+1 < len && s[i+1] == '/')
zs = 0;//在原文件中*/后面是换行符
else if(zs == 0)
printf("%c", s[i]);
}
}
}
接受3个以N/D的形式输入的分数,其中N为分子,D为分母,均在范围(0,65535)之间,输出他们的小数形式。如果小数存在循环节,则用括号括起来,如1/3=.33333…表示为0.(3)
例如:
输入:8/5 1/3 11/13
输出:
8/5=1.6
1/3=.(3)
11/13=.(846153)
解题思想:手动模拟除法过程。
如1/3,第一步p = 0,r = 1;
然后将余数r*10与3相除,得到商p = 3,余数为1
再来一次刚刚的步骤,p=3,r=1
可以看到当开始出现循环的时候,p对应的r的值是与之前一样的,这种关系在程序中可以用一个map实现对应关系。
同时要记录p的位置方便插入‘( ’,原因是前面的可能不是循环节如17/22 = 0.7(72)。
#include
#include
#include
using namespace std;
map<int, int> mp, pos;
string getr(int a, int b)
{
string res = "", f = "";//f存储小数部分
int p = a/b, r = a % b, rotate = 0, cnt = 0;//rotate记录是否找到循环节,cnt记录每一个小数所在位置
int index;//记录循环节的第一个数
if(p != 0)
res += to_string(p);//处理整数部分
res += '.';
while(r != 0)
{
p = r * 10 / b;
r = r * 10 % b;
if(r != 0 && mp[p] == r)//如果商与余数之前已经对应了,说明已经找到循环节
{
rotate = 1;//表示循环节已经找到
index = p;
break;
}
f += (p+'0');//用f保存小数部分
mp[p] = r;//记录商对应的余数
pos[p] = cnt++;//记录p在小数部分出现的位置,若p为循环节第一个,则(可以插入p在小数部分的位置
}
if(rotate == 1)
{
string c = "(";
f.insert(pos[index], c);
f += ')';
}
res += f;
return res;
}
int main()
{
int a, b;
while(~scanf("%d/%d", &a, &b))
{
mp.clear();
string res = getr(a, b);
printf("%s\n", res.c_str());
}
return 0;
}
测试样例
1/3
.(3)
11/13
.(846153)
17/22
.7(72)
8/5
1.6
7/3
2.(3)
题目:
无冗余输出一个字符串,对于不是首次出现的字符,对其进行过滤。如abcdacdef,过滤后为abcdef。对于字符0-9,a-f,A-F,将其对应的ASCII码低4位进行对调,例如将1101转换为1011,并将对应的ASCII码的字符进行输出,若为字母,转换为大写。
思路:对于ASCII码低四位颠倒,可以先取出低四位,用原数a与0fH进行与得到的结果给f,然后a减去f,这样a的低四位就为0。然后用一个循环去f的四位二进制,求出来的四位二进制与原来的位置相反,正好满足题目要求。再将求出来的二进制转化为十进制,然后将所得十进制加上a即可。
#include
#include
#include
#include
using namespace std;
int app[300];
int change(char a)
{
int f = a & (0x0f), total = 0;
a -= f;//清空低四位
string res = "";
while(f != 0)
{
int r = f % 2;
f /= 2;
res += (r+'0');
}//求二进制并加入res字符串中,二进制与原来的低四位相反
while(res.size() < 4)
res += '0';//求出来的二进制不足四位则低位补0
for(auto x : res)
total = total * 2 + (x-'0');//将求出的二进制转化为10进制
total += a;//加上原来的数后,原来的数的低四位就完成了倒置
return total;
}
int main()
{
string a;
while(cin >> a)
{
cout << a << endl;
memset(app, 0, sizeof(app));
string res = "";
for(auto i:a)
{
if(app[i] == 0)
{
cout << i;
app[i] = 1;
if((i >= '0' && i <= '9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F'))
{
char num = change(i);
if(num >= 'a')
num = num-'a'+'A';//若为小写字母,则转化为大写,小写字母ascii码大于大写字母
res += num;
}
}
}
cout << endl << res << endl;
}
}
题目:
输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串连续出现的字符串片段。回文的含义是:正着看和倒着看是相同的,如abba和abbebba。在判断是要求忽略所有的标点和空格,且忽略大小写,但输出时按原样输出(首尾不要输出多余的字符串)。输入字符串长度大于等于1小于等于5000
思路:这题求最长回文子串可以用动态规划来求,关键是如何处理标点符号。可以先将字符串中的空格、标点符号去除保存在res中,找到res的最长回文子串后再与原字符串比较,当比较的原字符串中的字符为标点或空格时就跳过,直到比完,说明此时找到了该字符串在原串中的位置。
最长回文子串(动态规划):参考博客链接
#include
#include
#include
#include
using namespace std;
bool is_char(char a)
{
if((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || (a >= '0' && a <= '9'))
return true;
else return false;
}//判断是否不是标点或空格
void find_pos(string s, string res, int &start, int &finish)
{
int index = 0;
for(int i = 0; i < s.length(); i++)
{
if(!is_char(s[i]))
continue;//原串中的字符是标点或空格则跳过
if(s[i] == res[index] || abs(s[i]-res[index]) == 32)
{//如果相等或一个为大写字母一个为小写字母
if(index == 0)
start = i;//找到最长回文子串在原串的起始位
index++;
if(index == res.length())
{
finish = i;
break;
}//如果比较到了最长回文子串末尾,则找到了
}
else
{
if(index != 0)
i--;//如果比较的是第一个字符,不相等则原串与子串均下移一位,如果比较的是第n个字符且不等,则子串从头开始比较,此时原串的位置不变。这里减一是为了与循环体的i++抵消。
index = 0;
}
}
}
int dp[5010][5010];
int main()
{
string s;
while(getline(cin, s))
{
string res="";
memset(dp, 0, sizeof(dp));
for(auto i:s)
{
if(is_char(i))
{
if(i >= 'A' && i <= 'Z')
i = i-'A'+'a';
res += i;
}//将所有大写字母转化为小写,忽略标点符号和空格
}
int len = res.length(), maxlen = 1, start = 0;//start为res中最长回文子串的起始位置
for(int i = 0; i < len; i++)
{
dp[i][i] = 1;
if(i+1 < len && res[i] == res[i+1])
{
dp[i][i+1] = 1;
maxlen = 2;
start = i;
}
}
for(int L = 3; L <= len; L++)
{
for(int i = 0; i+L-1 < len; i++)
{
int j = i+L-1;
if(res[i] == res[j] && dp[i+1][j-1] == 1)
{
dp[i][j] = 1;
maxlen = L;
start = i;
}
}
}
int left = 0, right = 0;//left,right分别为原串最长回文子串的起始位与结束位
find_pos(s, res.substr(start, maxlen), left, right);
cout << s.substr(left, right-left+1) << endl;
}
}