练习的故事仍然继续下去,今天写下的题目难度适中,记录自己近段时间的训练成果。涉及数学,动态规划,字符串问题。
poj 2159 Ancient Cipher(规律)
http://poj.org/problem?id=2159
大意:密码加密方法,两种加密方式,第一种,替换加密:Substitution cipher changes all occurrences of each letter to some other letter. Substitutes for all letters must be different(这就是当时做题坑的我一瘸一拐的 一句话).
第二种,排列加密:字符串乱序一下。
分析:那条语句就是精华啊啊啊,告诉我们,在得到每一个字符的出现次数后只需要排列比较是否一样就行。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char s1[105],s2[105];
int t1[30],t2[30];
int main()
{
//freopen("cin.txt","r",stdin);
while(~scanf("%s",s1)){
scanf("%s",s2);
memset(t1,0,sizeof(t1));
memset(t2,0,sizeof(t2));
int len1=strlen(s1),len2=strlen(s2);
for(int i=0;i<len1;i++) t1[s1[i]-'A']++;
for(int i=0;i<len2;i++) t2[s2[i]-'A']++;
bool same=1;
sort(t1,t1+30); sort(t2,t2+30);
for(int i=0;i<30;i++){
if(t1[i]!=t2[i]){ same=0; break; }
}
if(same) puts("YES");
else puts("NO");
}
return 0;
}
nefu 1174 Decode(reverse函数)
http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1174
大意:将字符串中的小串逆序,然后输出,如:
Sample Input
i evol uoy
doog emag
Sample Output
i love you
good game
linux下用不了个gets(),我的版本号是ubuntu 16.04 LTS:
main.cpp: In function ‘int main()’:
main.cpp:10:12: warning: ‘char* gets(char*)’ is deprecated [-Wdeprecated-declarations]
while(~gets(str)){
^
In file included from main.cpp:1:0:
/usr/include/stdio.h:638:14: note: declared here
extern char *gets (char *__s) __wur __attribute_deprecated__;
^
main.cpp:10:12: warning: ‘char* gets(char*)’ is deprecated [-Wdeprecated-declarations]
while(~gets(str)){
^
In file included from main.cpp:1:0:
/usr/include/stdio.h:638:14: note: declared here
extern char *gets (char *__s) __wur __attribute_deprecated__;
^
main.cpp:10:20: warning: ‘char* gets(char*)’ is deprecated [-Wdeprecated-declarations]
while(~gets(str)){
^
In file included from main.cpp:1:0:
/usr/include/stdio.h:638:14: note: declared here
extern char *gets (char *__s) __wur __attribute_deprecated__;
^
main.cpp:10:20: error: wrong type argument to bit-complement
while(~gets(str)){
掌握reverse函数的用法即可。
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <stdlib.h>
using namespace std;
char str[1005],s[1005];
int main(){
while(~scanf("%c",&str[0])){
if(str[0]==EOF) break;
int L=1;
while(scanf("%c",&str[L++]) && str[L-1]!='\n');
str[L-1]=0;
int top=0;
for(int i=0;str[i];i++){
if(str[i]==' '){
s[top]=0;
reverse(s,s+top); // 系统函数实现翻转
printf("%s ",s);
top=0;
}
else s[top++]=str[i];
}
s[top]=0;
reverse(s,s+top); // 系统函数实现翻转
printf("%s\n",s);
}
return 0;
}
问题拓展:
将字符串整体逆序,小串不逆序
如
asfd dfds fgh jkj
jkj fgh dfds asfd
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
char str[100][105],s[105];
char L[10005];
int main()
{
while(gets(L)){
int top=0,len=0;
for(int i=0;L[i];i++){
if(L[i]==' '){
s[top]=0;
strcpy(str[len++],s);
top=0;
}
else s[top++]=L[i];
}
s[top]=0;
strcpy(str[len++],s);
reverse(str,str+len);
for(int i=0;i<len-1;i++){
printf("%s ",str[i]);
}
printf("%s\n",str[len-1]);
}
return 0;
}
codeforces 645B. Mischievous Mess Makers(贪心)
http://codeforces.com/problemset/problem/645/B
大意:给出一个1-n的序列,最多进行k次交换,问最大的逆序数是多少?
分析:为了得到最大的逆序数,我们需要交换右边最大的数字和左边最小的数字。最开始的数字有n个,交换一次剩下n-2个数字……如果n是偶数,最后剩下是2个;是奇数的話最后剩下3个。每交换一次,产生的逆序数是n-1+1+1+……+0=2n-3
eg:
1 2 3 4 5
5 2 3 4 1
–>
4 1 1 1 0
设最小n是minm=min(2,n-2k+2) OR min(3,n-2k+2),交换次数c= (n-minm)/2+1
所以最后的逆序数就是2(n+n-2+……+minm)-3c
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
int main()
{
LL n,k;
while(cin>>n>>k){
if(n==1) {
puts("0"); continue;
}
LL minm=0;
if(n&1) minm=max(3LL,n-2*k+2);
else minm=max(2LL,n-2*k+2); //min n
LL c=(n-minm)/2+1; //swap counts
LL s=c*(n+minm)/2;
s=s*2-3*c;
printf("%I64d\n",s);
}
return 0;
}
nefu 1173 Dipper Landlord(规律)
http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1173
大意:斗地主游戏。每一次游戏有一个地主两个农民, x=6×2y ,地主赢了加分2x,农民减分x, 农民赢了都加分x, 地主减分2x。现在给出三个数字,问是否合法。
分析:地主每次的变化量是2x,两个农民的变化量是每人x。这样看来它们任意两个数字的差值的绝对值是3x的倍数。同时三个数的和是3000。
当时的思路是比较复杂的。我想着地主,农民,农民: x(2k) -xk -xk
x需要满足的形式是 6×2y , 然后直接判断即可。代码写了老长了,结果还错了T_T
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int r[3];
while(cin>>r[0]>>r[1]>>r[2]){
int sum=r[0]+r[1]+r[2];
int d1=r[0]-r[1];
int d2=r[1]-r[2];
int d3=r[0]-r[2];
if(sum==3000 && d1%18==0 && d2%18==0 && d3%18==0) puts("Yes");
else puts("No");
}
return 0;
}
poj 2262 Goldbach’s Conjecture(简单)
http://poj.org/problem?id=2262
大意:求解6-1000000内的偶数能否写成两个素数之和。
分析:练手
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
const int N=1e6+10;
vector<int> prim;
int cnt;
bool vis[N];
void getprim(){
for(int i=2;i<N;i++){
if(!vis[i]) prim.push_back(i);
cnt=prim.size();
for(int j=0;j<cnt && prim[j]*i<N;j++){
vis[i*prim[j]]=1;
if(i%prim[j]==0) break;
}
}
}
int main()
{
getprim();
int n;
while(cin>>n&&n){
bool tag=0;
for(int i=1;prim[i]+prim[i]<=n;i++){
int g=n-prim[i];
if(vis[g]==0) {
printf("%d = %d + %d\n",n,prim[i],g);
tag=1;
break;
}
}
if(tag==0) puts("Goldbach's conjecture is wrong.");
}
return 0;
}
nyist 368 最长公共子序列(简单)
http://acm.nyist.net/JudgeOnline/problem.php?pid=36&rec=rec
只要求输出字符串的长度:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
char s1[1005],s2[1005];
int g[1005][1005];
int main(){
//freopen("cin.txt","r",stdin);
int t;
cin>>t;
while(t--){
scanf("%s%s",s1+1,s2+1);
memset(g,0,sizeof(g));
for(int i=1;s1[i];i++){
for(int j=1;s2[j];j++){
if(s1[i]==s2[j]){
g[i][j]=g[i-1][j-1]+1;
}
else {
g[i][j]=max(g[i-1][j],g[i][j-1]); //当两者不同时,两个串的当前字符都可能成为LCS的一部分
}
}
}
int len1=strlen(s1+1),len2=strlen(s2+1);
printf("%d\n",g[len1][len2]);
}
return 0;
}
问题拓展:
要求输出最长的相同字符子串:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
char s1[1005],s2[1005];
int g[1005][1005];
int dir[1005][1005];
int main(){
//freopen("cin.txt","r",stdin);
int t;
cin>>t;
while(t--){
scanf("%s%s",s1+1,s2+1);
memset(g,0,sizeof(g));
memset(dir,-1,sizeof(dir));
for(int i=1;s1[i];i++){
for(int j=1;s2[j];j++){
if(s1[i]==s2[j]){
g[i][j]=g[i-1][j-1]+1;
dir[i][j]=1; // 左斜上方
}
else {
if(g[i-1][j]>g[i][j-1]) { g[i][j]=g[i-1][j]; dir[i][j]=0; } //上方
else { g[i][j]=g[i][j-1]; dir[i][j]=2; } //左边
}
}
}
int len1=strlen(s1+1),len2=strlen(s2+1);
printf("%d\n",g[len1][len2]);
int x=len1, y=len2, top=0;
char str[1005];
memset(str,0,sizeof(str));
while(x>0 && y>0){
if(s1[x]==s2[y]) str[top++]=s1[x];
if(dir[x][y]==0) x--;
else if(dir[x][y]==1){ x--; y--; }
else if(dir[x][y]==2){ y--; }
}
while(top>0){
printf("%c",str[top-1]);
top--;
}
puts("");
}
return 0;
}
codeforces 645A. Amity Assessment(规律)
http://codeforces.com/problemset/problem/645/A
大意:
能否通过变换使得两者具有相同的结构?
分析:空格相邻的字母来填补空格不会变化的是顺时针的字母顺序。于是整个问题就变成了数组位移问题。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
char B[2][5],E[2][5];
char s1[5],s2[5];
void moves(char ss[]){
char ch=ss[2];
ss[2]=ss[1]; ss[1]=ss[0]; ss[0]=ch;
}
int main()
{
while(~scanf("%s",B[0])){
scanf("%s%s%s",B[1],E[0],E[1]);
s1[0]=B[0][0]; s1[1]=B[0][1]; s1[2]=B[1][1]; s1[3]=B[1][0];
s2[0]=E[0][0]; s2[1]=E[0][1]; s2[2]=E[1][1]; s2[3]=E[1][0];
for(int i=0;i<4;i++){
if(s1[i]=='X') {
for(int j=i;j<4;j++) s1[j]=s1[j+1];
}
if(s2[i]=='X') {
for(int j=i;j<4;j++) s2[j]=s2[j+1];
}
}
bool same=0;
for(int i=0;i<3;i++){
if(strcmp(s1,s2)==0) { same=1; break; }
moves(s1);
}
if(same) puts("YES");
else puts("NO");
}
return 0;
}
hdu 3853 LOOPS(概率dp)
http://acm.hdu.edu.cn/showproblem.php?pid=3853
大意:逃离迷宫,从左上角出发,到达右下角算是成功逃脱。每一个点有三条路径可选,自身,右边,下边,他们的选择概率分别给出,每一次跳跃格子都将花费2份魔力,问逃离迷宫的花费魔力的期望
分析:
假设点(i,j)选择自身,右边,下边的概率分别是
p[i][j][0] , p[i][j][1] , p[i][j][2] 。