A题
大数加法
给出2个大整数A,B,计算A+B的结果。
Input
第1行:大数A
第2行:大数B
(A,B的长度 <= 10000 需注意:A B有可能为负数)
Output
输出A + B
Sample Input
68932147586
468711654886
Sample Output
537643802472
很简单的一道高精度,不过,挺考验人的耐心
一个大数加法,一个大数减法,然后判断A,B的正负,总共4种情况
A正B正——直接输出
A负B负——输出负的(|A|+|B|)
A正B负——输出A-B
A负B正——输出B-A
代码:
#include<iostream>
using namespace std;
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#define M 20000
int pd(char a[],char b[])
{
inti,j;
int len1=strlen(a);
int len2=strlen(b);
//cout<<len1<<" "<<len2<<endl;
if (len1>len2) return 1;
if (len1<len2) return 0;
for (i=0;i<=len1;i++)
{
if (a[i]<b[i])
{
// cout<<"\t"<<a[i]<<""<<b[i]<<endl;
return 0;
}
if (a[i]>b[i])
{
return 1;
}
}
return1;
}
void xf(char s1[],char s2[])
{
inti,j;
intt=0;
intc1=0,c2=0;
intl1=strlen(s1),l2=strlen(s2);
if(s1[0]=='-') c1++;
if(s2[0]=='-') c2++;
for(i=c1;i<l1;i++)
{
if(s1[i]=='0') {
t++;continue;}
break;
}
if(t==l1) {
s1[0]=48;s1[1]=0;
}
if(t>0)
for(i=c1;i<=l1-t;i++)
s1[i]=s1[i+t];
t=0;
for(i=c2;i<l2;i++)
{
if(s2[i]=='0') {
t++;continue;}
break;
}
if(t>0)
for(i=c2;i<=l2-t;i++)
s2[i]=s2[i+t];
if(t==l2) {
s2[0]=48;s2[1]=0;
}
}
void xf2(char s1[])
{
inti,j;
intt=0;
intc1=0;
intl1=strlen(s1);
if(s1[0]=='-') c1++;
for(i=c1;i<l1;i++)
{
if(s1[i]=='0') {
t++;continue;}
break;
}
if(t==l1) {
s1[0]=48;s1[1]=0;
}
if(t>0)
for(i=c1;i<=l1-t;i++)
s1[i]=s1[i+t];
}
int num1[M],num2[M];
void jian(char s1[],char s2[],char t[])
{
int i,j;
int len1=strlen(s1);
int len2=strlen(s2);
int a=max(len1,len2);
for (i=0;i<=a+3;i++)
num1[i]=num2[i]=0;
for(i=len1-1,j=0;i>=0;i--)
num1[j++]=s1[i]-'0';
for(i=len2-1,j=0;i>=0;i--)
num2[j++]=s2[i]-'0';
for (i=0;i<a;i++)
{
num1[i]=num1[i]-num2[i];
if (num1[i]<0)
{
num1[i]=10+num1[i];
num1[i+1]--;
}
// cout<<num1[i];
}
i=a-1;
while(i>=0&&num1[i]==0) i--;
if (i<0)
{
t[0]='0';t[1]=0;
return;
}
a=i+1;
for (i=0;i<a;i++)
{
t[i]=num1[a-1-i]+48;
//cout<<t[i];
//cout<<t[i]<<""<<num1[a-1-i]<<" "<<i<<endl;
}
t[a]=0;
}
void Add(char s1[],char s2[],char t[])
{
int num1[M],num2[M];
int i,j;
int len1=strlen(s1);
int len2=strlen(s2);
int a=max(len1,len2);
for (i=0;i<=a+3;i++)
num1[i]=num2[i]=0;
for(i=len1-1,j=0;i>=0;i--)
num1[j++]=s1[i]-'0';
for(i=len2-1,j=0;i>=0;i--)
num2[j++]=s2[i]-'0';
for(i=0;i<a;i++)
{
num1[i]+=num2[i];
if(num1[i]>9)
{
num1[i]-=10;
num1[i+1]++;
}
}
if (num1[i]>0) a++;
for (i=0;i<a;i++)
{
t[i]=num1[a-1-i]+48;
//cout<<t[i]<<""<<num1[a-1-i]<<" "<<i<<endl;
}
t[a]=0;
//cout<<endl;
}
char c[11000],a[11000],b[11000];
int main()
{
cin>>a>>b;
xf(a,b);
if(a[0]=='-'&&b[0]=='-')
{
intl1=strlen(a),l2=strlen(b);
Add(a+1,b+1,c);
intl=strlen(c);
if(c[0]=='0'&&strlen(c)==1||strlen(c)==0)
{
cout<<"-";
intj;
for(j=0;j<l;j++)
{
if(c[j]!='0') break;
}
if(j==l) j=0;
cout<<0;
return0;
}
cout<<"-";
intj;
for(j=0;j<l;j++)
{
if(c[j]!='0') break;
}
if(j==l) j=0;
for(int i=0;i<l;i++)
cout<<c[i];
return0;
}
if(a[0]=='-'&&b[0]!='-')
{
intl1=strlen(a);
intl2=strlen(b);
//cout<<l1<<""<<l2<<endl;
intt=pd(b,a+1);
// cout<<"sda"<<t<<endl;
if(t)
{
jian(b,a+1,c);
int l=strlen(c);
intj;
for(j=0;j<l;j++)
{
if(c[j]!='0') break;
}
if(j==l) j=0;
for(int i=0;i<l;i++)
cout<<c[i];
return0;
}
jian(a+1,b,c);
intl=strlen(c);
cout<<"-";
intj;
for(j=0;j<l;j++)
{
if(c[j]!='0') break;
}
if(j==l) j=0;
for(int i=0;i<l;i++)
cout<<c[i];
return0;
}
//jian(a,b,c);
if(a[0]!='-'&&b[0]=='-')
{
intl1=strlen(b);
intt=pd(a,b+1);
// cout<<t<<"sadas"<<endl;
if(t)
{
jian(a,b+1,c);
intl=strlen(c);
intj;
for(j=0;j<l;j++)
{
if(c[j]!='0') break;
}
if(j==l) j=0;
for(int i=0;i<l;i++)
cout<<c[i];
return0;
}
jian(b+1,a,c);
intl=strlen(c);
cout<<"-";
intj;
for(j=0;j<l;j++)
{
if(c[j]!='0') break;
}
if(j==l) j=0;
for(int i=0;i<l;i++)
cout<<c[i];
return0;
}
Add(a,b,c);
intl=strlen(c);
intj;
for(j=0;j<l;j++)
{
if(c[j]!='0') break;
}
if(j==l) j=0;
for(int i=j;i<l;i++)
cout<<c[i];
return0;
}
B.Bash游戏
有一堆石子共有N个。A B两个人轮流拿,A先拿。每次最少拿1颗,最多拿K颗,拿到最后1颗石子的人获胜。假设A B都非常聪明,拿石子的过程中不会出现失误。给出N和K,问最后谁能赢得比赛。
例如N = 3,K = 2。无论A如何拿,B都可以拿到最后1颗石子。
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000)
第2 - T + 1行:每行2个数N,K。中间用空格分隔。(1 <= N,K <= 10^9)
Output
共T行,如果A获胜输出A,如果B获胜输出B。
Sample Input
4
3 2
4 2
7 3
8 3
Sample Output
B
A
A
B
题解:
纯粹考验智商,如果(K+1)| N那么B赢,否则A赢
证明——脑子是个好东西,然鹅我并没有,看别的博客吧。。。。。。。
代码:
#include<cstdio>
#include<iostream>
using namespace std;
int deal()
{
int n,k;
cin>>n>>k;
if(n<=k)
{
cout<<"A\n";
return 0;
}
if(n%(k+1)==0)
{
cout<<"B\n";
return 0;
}
else{
cout<<"A\n";
return 0;
}
}
int main()
{
int t;
cin>>t;
while(t--)
deal();
}
C - 逆序数
在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。
Input
第1行:N,N为序列的长度(n <= 50000)
第2 - N + 1行:序列中的元素(0 <= Aii <= 10^9)
Output
输出逆序数
Sample Input
4
2
4
3
1
Sample Output
4
题解:
归并排序输出逆序数
代码:
#include<iostream>
using namespace std;
#include<cmath>
int a[1000000],b[1000000];
int ans=0;
void merge(int a[],int b[],int l,int r,intrend)
{
int t=l;
intpl=l,pr=r;
intmid=r-1;
intne=abs(l-rend)+1;
// for(inti=l;i<=rend;i++)
//cout<<a[i]<<"";
// cout<<endl;
while(pl<=mid&&pr<=rend)
{
if(a[pl]<=a[pr])
{
b[t++]=a[pl++];
}
else
{
b[t++]=a[pr++];
// cout<<"\t\t"<<b[t-1]<<""<<mid-pl+1<<endl;
ans+=mid-pl+1;
}
}
while(pl<=mid){
b[t++]=a[pl++];}
while(pr<=rend){
b[t++]=a[pr++];}
for (int i=0;i<ne;i++,rend--)
{
a[rend]=b[rend];
}
}
int mergesort(int a[],int b[],int l,int r)
{
if(l<r)
{
intmid=(l+r)/2;
// cout<<l<<""<<r<<endl;
mergesort(a,b,l,mid);
mergesort(a,b,mid+1,r);
// cout<<"\tmerge:"<<l<<""<<mid+1<<" "<<r<<endl;
merge(a,b,l,mid+1,r);
}
}
int main()
{
int n;
cin>>n;
int i;
for (i=0;i<n;i++)
cin>>a[i];
mergesort(a,b,0,n-1);
cout<<ans;
}
D - N的阶乘的长度
输入N求N的阶乘的10进制表示的长度。例如6! = 720,长度为3。
Input
输入N(1 <= N <= 10^6)
Output
输出N的阶乘的长度
Sample Input
6
Sample Output
3
题解:
n!=(n*(n-1)*(n-2)*…*2*1)
f(n)表示n的位数
f(n)=lgn+1;
f(n)=lg((n*(n-1)*(n-2)*…*2*1))=lg(n)+lg(n-1)+…+lg(2)+lg(1)+1;
代码:
#include<iostream>
using namespace std;
#include<cmath>
int main()
{
int n;
cin>>n;
long long ans;
double s=1;
for (int i=1;i<=n;i++)
{
s+=log10(i);
}
ans=s;
cout<<ans;
}
E - 机器人走方格
M * N的方格,一个机器人从左上走到右下,只能向右或向下走。有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 10^9 + 7的结果。
Input
第1行,2个数M,N,中间用空格隔开。(2 <= m,n <= 1000)
Output
输出走法的数量。
Sample Input
2 3
Sample Output
3
题解:
记忆化搜索
f[i][j]表示以i,j为终点的方法数
因为机器人只能往下走或者往右走所以:
f[i][j]=f[i-1][j]+f[i][j-1]
初始化;f[1][1]=1;
代码:
#include<iostream>
using namespace std;
const int mod=1000000007;
int f[1010][1010],v[1010][1010];
int dfs(int x,int y)
{
if(x<=0||y<=0) return 0;
if (x==1&&y==1) return 1;
if(v[x][y]) return f[x][y];
int ans;
v[x][y]=1;
ans=(dfs(x-1,y)%mod+dfs(x,y-1)%mod)%mod;
f[x][y]=ans;
return ans;
}
int main()
{
int m,n;
cin>>m>>n;
cout<<dfs(m,n)<<endl;
}
F - 编辑距离
编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
例如将kitten一字转成sitting:
sitten (k->s)
sittin (e->i)
sitting (->g)
所以kitten和sitting的编辑距离是3。俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。
给出两个字符串a,b,求a和b的编辑距离。
Input
第1行:字符串a(a的长度 <= 1000)。
第2行:字符串b(b的长度 <= 1000)。
Output
输出a和b的编辑距离
Sample Input
kitten
sitting
Sample Output
3
题解:
设f[i][j]为以字符串a第i个位置与字符串b第j个位置为终点,需要更改的最小次数
所以就很容易想到状态转移方程:
f[i][j]=min(f[i-1][j]+1,f[i][j-1]+1,f[i-1][j-1]+t);
如果a[i]==a[j]的话t=0否则t=1;
坑点:
初始化,
i=1…strlen(A)
f[i][0]=i
J=1…STRLEN(B)
f[0][j]=j
代码:
#include<iostream>
using namespace std;
#include<string>
#include<cmath>
string a,b;
int f[2000][2000],v[2000][2000];
int main()
{
cin>>a>>b;
intl1=a.length(),l2=b.length();
int i,j;
for (i=0;i<=l1+1;i++)
{
f[i][0]=i;
v[i][0]=1;
}
for (i=0;i<=l2+1;i++)
{
f[0][i]=i;
v[0][i]=1;
}
for (int i=1;i<=l1;i++)
for (int j=1;j<=l2;j++)
{
intcost;
cost=(a[i-1]==b[j-1])?0:1;
f[i][j]=min(min(f[i-1][j]+1,f[i][j-1]+1),f[i-1][j-1]+cost);
}
cout<<f[l1][l2];
}