题目就不赘述了,来源51nod网站。
这道题是一道非常好想的二维dp问题,可以在不选当前行,不选当前列的情况下(dp[i+1][j+1]=dp[i][j]+1),若两个字符串中的字符相等,则有在原来的子序列基础上又增加一个字符;若两个字符串中的字符不相等,则寻找到此为止的最大的子序列的长度是多少,把值赋给它。
dp[i][j]:表示第一个字符串取(0,i-1),第二个字符串为(0,j-1),最长的公共子序列是多长。
最后在记录长度的同时,记录这个子序列的长度是怎么加过来的,记录完毕后从终点回溯到起点,用字符串保存回溯中找到的子序列的字符,翻转(因为是从终点到起点),输出。
#include
using namespace std;
const int maxn=1010;
int dp[maxn][maxn];
char opp[maxn][maxn];
int main(){
string s,str;
cin>>s>>str;
dp[0][0]=0;
for(int i=0;i<s.size();i++){
for(int j=0;j<str.size();j++){
if(s[i]==str[j]){
dp[i+1][j+1]=dp[i][j]+1;
opp[i][j]='x';
}else{
if(dp[i][j+1]>dp[i+1][j]){
dp[i+1][j+1]=dp[i][j+1];
opp[i][j]='d';
}else{
dp[i+1][j+1]=dp[i+1][j];
opp[i][j]='r';
}
}
}
}
string ans;
int x=s.size()-1,y=str.size()-1;
while(x>=0&&y>=0){
if(opp[x][y]=='x'){
ans+=s[x];
x--;
y--;
}else if(opp[x][y]=='d'){
x--;
}else{
y--;
}
}
reverse(ans.begin(),ans.end());
cout<<ans<<endl;
//system("pause");
return 0;
}
这就有点灵性了,乱写了一个,模拟的加减法竖式。
调了半天,没考虑前置零,考虑了之后又忘了还有结果为零的情况。
然后就分类讨论就可,我确实是写麻烦了,就当练练大模拟了。
#include
using namespace std;
string add(string a,string b){
int fa=1,fb=1;
int lena=a.size(),lenb=b.size();
if(a[0]<'0'||a[0]>'9') fa=-1,a=a.substr(1,lena-1),lena--;
if(b[0]<'0'||b[0]>'9') fb=-1,b=b.substr(1,lenb-1),lenb--;
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
string ans;
int shi=0;
int tem=0;
int aa=0,bb=0;
ans="";
if((fa>0 && fb<0) || (fa<0 && fb>0)){
//a-b
if(lena>lenb || (lena==lenb && a[lena-1]>b[lenb-1])){
for(int i=0;i<lenb;i++){
aa=a[i]-'0';
bb=b[i]-'0';
tem=aa-bb+shi;
if(tem<0){
tem=tem+10;
shi=-1;
}else{
shi=0;
}
ans+=(tem+'0');
}
for(int i=lenb;i<lena;i++){
aa=a[i]-'0';
tem=aa+shi;
if(tem<0){
tem=tem+10;
shi=-1;
}else{
shi=0;
}
ans+=(tem+'0');
}
}else{
for(int i=0;i<lena;i++){
aa=a[i]-'0';
bb=b[i]-'0';
tem=bb-aa+shi;
if(tem<0){
tem=tem+10;
shi=-1;
}else{
shi=0;
}
ans+=(tem+'0');
}
for(int i=lena;i<lenb;i++){
bb=b[i]-'0';
tem=bb+shi;
if(tem<0){
tem=tem+10;
shi=-1;
}else{
shi=0;
}
ans+=(tem+'0');
}
ans+='-';
}
//b-a
if(fa<0 && fb>0){
int len=ans.size();
if(ans[len-1]=='-') ans=ans.substr(0,len-1);
else ans+='-';
}
}else{
//(a+b) or -(a+b)
if(lena>lenb){
for(int i=0;i<lenb;i++){
aa=a[i]-'0';
bb=b[i]-'0';
tem=aa+bb+shi;
shi=tem/10;
tem=tem%10;
ans+=(tem+'0');
}
for(int i=lenb;i<lena;i++){
aa=a[i]-'0';
tem=aa+shi;
shi=tem/10;
tem=tem%10;
ans+=(tem+'0');
}
}else{
for(int i=0;i<lena;i++){
aa=a[i]-'0';
bb=b[i]-'0';
tem=aa+bb+shi;
shi=tem/10;
tem=tem%10;
ans+=(tem+'0');
}
for(int i=lena;i<lenb;i++){
bb=b[i]-'0';
tem=bb+shi;
shi=tem/10;
tem=tem%10;
ans+=(tem+'0');
}
}
if(shi) ans+=(shi+'0');
if(fa<0) ans+='-';
}
int cnt=0;
int f=0;
int len=ans.size();
for(int i=len-1;i>=0;i--){
if(ans[i]=='-'){
f=1;
continue;
}
if(ans[i]=='0') cnt++;
else break;
}
if(f) cnt++;
ans=ans.substr(0,len-cnt);
if(ans==""){
return "0";
}
if(f) ans+='-';
reverse(ans.begin(),ans.end());
return ans;
}
int main(){
string a,b;
cin>>a>>b;
string ans;
ans=add(a,b);
cout<<ans<<endl;
//system("pause");
return 0;
}
day2
#include
using namespace std;
const int maxn=50010;
typedef long long ll;
ll a[maxn],b[maxn];
ll cnt;
void merge_sort(int l,int r){
if(r-l>0){
int mid=(l+r)/2;
int i=l;
int p=l,q=mid+1;
merge_sort(l,mid);
merge_sort(mid+1,r);
while(p<=mid || q<=r){
if(q>r||(p<=mid&&a[p]<=a[q])){
b[i++]=a[p++];
}else{
b[i++]=a[q++];
cnt=cnt+mid-p+1;
}
}
for(i=l;i<=r;i++){
a[i]=b[i];
}
}
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
merge_sort(1,n);
cout<<cnt<<endl;
//system("pause");
return 0;
}
#include
using namespace std;
const int maxn=50010;
typedef long long ll;
ll a[maxn],b[maxn];
ll ans;
ll t[maxn];
int n;
int lowbit(int x){
return x&-x;
}
void add(int x){
while(x<=n){
t[x]++;
x+=lowbit(x);
}
}
ll sum(int x){
ll res=0;
while(x>=1){
res+=t[x];
x-=lowbit(x);
}
return res;
}
bool cmp(int x,int y){
if(a[x]==a[y]) return x>y;
return a[x]>a[y];
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=i;
}
sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++){
add(b[i]);
ans+=sum(b[i]-1);
}
cout<<ans<<endl;
return 0;
}
依旧大模拟,写的时候出了点差错:
terminate called after throwing an instance of ‘std::out_of_range’ what(): basic_string::substr
解决方案:查找substr方法前后代码,排除可能的越界条件。
其它的异常顺利。
#include
using namespace std;
const int maxn=50010;
typedef long long ll;
string add(string a,string b){
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
string ans;
int shi=0;
int tem=0;
int aa=0,bb=0;
int lena=a.size(),lenb=b.size();
ans="";
for(int i=0;i<lena;i++){
aa=a[i]-'0';
bb=b[i]-'0';
tem=aa+bb+shi;
shi=tem/10;
tem=tem%10;
ans+=(tem+'0');
}
for(int i=lena;i<lenb;i++){
bb=b[i]-'0';
tem=bb+shi;
shi=tem/10;
tem=tem%10;
ans+=(tem+'0');
}
if(shi) ans+=(shi+'0');
int cnt=0;
int len=ans.size();
for(int i=len-1;i>=0;i--){
if(ans[i]=='0') cnt++;
else break;
}
ans=ans.substr(0,len-cnt);
if(ans==""){
return "0";
}
reverse(ans.begin(),ans.end());
return ans;
}
string mul(string a,string b){
int fa=1,fb=1;
int lena=a.size(),lenb=b.size();
if(a[0]=='-'){
fa=-1;a.substr(1,lena-1);lena--;}
if(b[0]=='-'){
fb=-1;b.substr(1,lenb-1);lenb--;}
reverse(a.begin(),a.end());
reverse(b.begin(),b.end());
if(lenb>lena){
string temp=a;
a=b;
b=temp;
int tt=lena;
lena=lenb;
lenb=tt;
}
vector<string> ve;
int num=0;
for(int i=0;i<lenb;i++){
string ans;
int p=b[i]-'0';
int shi=0;
for(int j=0;j<lena;j++){
num=(a[j]-'0')*p+shi;
shi=num/10;
num%=10;
ans+=(num+'0');
}
string sh;
sh="";
sh=(shi+'0');
ans+=sh;
reverse(ans.begin(),ans.end());
for(int j=0;j<i;j++){
ans+="0";
}
ve.push_back(ans);
shi=0;
num=0;
}
string s,str;
s=ve[0];
for(int i=1;i<ve.size();i++){
s=add(s,ve[i]);
}
int cnt=0;
int len=s.size();
for(int i=0;i<len;i++){
if(s[i]=='0') cnt++;
else break;
}
s=s.substr(cnt,len-cnt);
if(s==""){
return "0";
}
if(fa<0 && fb<0){
;
}else if(fa>0 && fb>0){
;
}else{
str="-";
}
str+=s;
return str;
}
int main(){
string a,b;
cin>>a>>b;
cout<<mul(a,b)<<endl;
//system("pause");
return 0;
}
day3
思路是:用一个 A [ i ] A[i] A[i]数组储存,每个数组中储存14位数,能把运算控制在long long 的范围之中,第一重循环写的是该乘哪个数了(1~n中),第二重是用了几个 A [ i ] A[i] A[i],用了 l l l个。 c c c保存的是存不下的进位数,如果有,放到下一个 A [ i ] A[i] A[i]中,并用 l l l更新,最后通过循环输出结果,把数组拼接在一起展示。
printf("%0.14lld",...);
//表示取十四位长整型数输出
#include
using namespace std;
typedef long long ll;
#define mod 100000000000000
ll A[10000000];
int main(){
ll n;
scanf("%lld",&n);
A[0]=1;
ll i,j,l=0;
for(i=1;i<=n;i++){
ll c=0;
for(j=0;j<=l;j++){
ll t=A[j]*i+c;
A[j]=t%mod;
c=t/mod;
}
if(c!=0){
A[++l]=c;
}
}
printf("%lld",A[l]);
for(int i=l-1;i>=0;i--){
printf("%0.14lld\n",A[i]);
}
//system("pause");
return 0;
}
根据对数的性质: l o g 10 ( x ) log10(x) log10(x), x x x如果是10,结果为1,一位;为100,结果是2,三位…
我们可以总结出, n ! n! n!有多少位,就是算 l o g 10 ( n ! ) log10(n!) log10(n!)的结果再加一。
数据范围是 1 0 6 10^6 106,我们可以用线性的累加法做出结果。
最后取整的时候用了floor函数,但是在小数点位数很多的时候发生了错误;采用强制取整,得到了最终正确的答案。
#include
using namespace std;
int main(){
double ans=0;
int n;
cin>>n;
for(int i=1;i<=n;i++){
ans+=log10(i*1.0);
}
cout<<ans<<endl;
cout<<(long long)(ans)+1<<endl;
//system("pause");
return 0;
}
A,B两个人拿一堆石子,共n个,每次取[1,k]个,谁先拿完谁赢。轮流拿,A先手。
如果n是k+1的倍数,那么无论A取任意值x,B只要取k+1-x即可保证必胜。
同理,若n不是k+1的倍数,那么只要第一步取n%(k+1),然后就相当于AB换了身份,显然A必胜。
#include
using namespace std;
typedef long long ll;
ll n,k;
int t;
int main(){
cin>>t;
while(t--){
cin>>n>>k;
if(n%(k+1)) cout<<"A"<<endl;
else cout<<"B"<<endl;
}
return 0;
}
A,B两人拿n堆石子,每堆石子 [ 1 , ∞ ] [1,\infty] [1,∞]个,每次可以最少拿一个,最多拿一堆,最先拿完的获胜。A先手。
#include
using namespace std;
typedef long long ll;
int n;
ll a;
ll ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a;
ans^=a;
}
if(ans) cout<<"A"<<endl;
else cout<<"B"<<endl;
//system("pause");
return 0;
}