ACM4.3对抗赛DEF题题解(原来如此简单,超级详细入门必备)

D:heilong的烦恼

题目传送门

题意:根据运算符决定运算,最后输出运算结果

思路:循环+数组存储

因为代码实在是太长了,我才你一定不怎么会看所以我先将核心进位代码写在这里

加法进位:

    c[i]=a[i]+b[i];
	if(c[i]>=10){
		c[i]%=10;
		c[i+1]++;
	}

减法进位:

    if(a[i]<b[i]){
		a[i+1]--;
		a[i]+=10;
	}
	c[i]=a[i]-b[i];

乘法进位:

    c[i+j-1]=a[i]*b[j]+x+c[i+j-1];
	x=c[i+j-1]/10;
	c[i+j-1]%=10;

至于除法:

用减法来模拟除法,对于被除数的每一位都减去除数,一直减到当前位置的数字(包含前面的余数)小于除数(由于每一位的数组小于10,所以对于每一位最多进行10次运算)

好了现在我们来看看具体代码是怎么写的

加法运算:

void jiafa(){
	int lena,lenb,lenc,i,j,k,x;
	string s,ss;
	cin>>s;
	cin>>ss;
	lena=s.size();
	lenb=ss.size();
	fe(i,0,lena-1)a[lena-i]=s[i]-'0';//这里我们要先将字符串化成数组
	fe(i,0,lenb-1)b[lenb-i]=ss[i]-'0';//
	lenc=1;
	x=0;
	while(lenc<=lena||lenc<=lenb){//直接相加,然后加的时候考虑进位
		c[lenc]=a[lenc]+b[lenc]+x;
		x=c[lenc]/10;
		c[lenc]%=10;
		lenc++;
	}
	c[lenc]=x;
	if(c[lenc]==0)lenc--;//由于我们是直接相加,所以当两个数的长度不同的时候,我们是存在前导0的
	de(i,lenc,1)cout<<c[i];
	cout<<endl;
	return;
}

下面是减法运算:在开始减法运算前,我们需要知道,用大数减去小数是最简单的,所以我们先判断前面的那个数是大数还是小数,如果是小数的话我们就需要先输出一个“-”。

void jianfa(){
	int lena,lenb,lenc,i,j,k,x;
	string s,ss;
	cin>>s;
	cin>>ss;
	lena=s.size();
	lenb=ss.size();
	if(lena<lenb||(lena==lenb&&s<ss)){
		swap(lena,lenb);
		swap(s,ss);                //由于我们的string是可以直接进行比较的所以我们没有
		cout<<"-";                 //必要转化了数组再去比较,直接比
	}
	fe(i,0,lena-1)a[lena-i]=s[i]-'0';//处理字符串
	fe(i,0,lenb-1)b[lenb-i]=ss[i]-'0';
	i=1;
	while(i<=lena||i<=lenb){//进行减法的时候,考虑什么时候会被借位
		if(a[i]<b[i]){
			a[i]+=10;
			a[i+1]--;
		}
		c[i]=a[i]-b[i];
		i++;
	}
	lenc=i;
	while(c[lenc]==0&&lenc>1)lenc--;//老规矩处理前导0
	de(i,lenc,1)cout<<c[i];
	cout<<endl;
	return;
}

乘法运算:

void chengfa(){
	int lena,lenb,lenc,i,j,k,x;
	string s,ss;
	cin>>s;
	cin>>ss;
	lena=s.size();
	lenb=ss.size();
	fe(i,0,lena-1)a[lena-i]=s[i]-'0';//处理字符串
	fe(i,0,lenb-1)b[lenb-i]=ss[i]-'0';
	fe(i,1,lena){//处理数组和进位问题
		x=0;
		fe(j,1,lenb){
			c[i+j-1]=a[i]*b[j]+x+c[i+j-1];//当前乘积+上次乘积进位+原数
			x=c[i+j-1]/10;
			c[i+j-1]%=10;
		}
		c[i+lenb]=x;                        //进位
	}
	lenc=lena+lenb;
	while(c[lenc]==0&&lenc>1)lenc--;//别忘记删除前导0
	de(i,lenc,1)cout<<c[i];
	cout<<endl;
	return;
}

除法这几个里面较难的一个,下面我们看看把

int compare(){//比较现在的a和tmp的大小
	int i;
	if(a[0]>tmp[0])return 1;
	if(a[0]<tmp[0])return -1;
	de(i,a[0],1){
		if(a[i]>tmp[i])return 1;
		if(a[i]<tmp[i])return -1;
	}
	return 0;
}
void jian(){
	int flag,i;
	flag=compare();
	if(!flag){
		a[0]=0;
		return ;
	}
	if(flag==1){
		fe(i,1,a[0]){
			if(a[i]<tmp[i]){
				a[i+1]--;
				a[i]+=10;
			}
			a[i]-=tmp[i];
		}
		while(a[0]>0&&a[a[0]]==0)a[0]--;
		return;
	}
}
void chufa(){
	int lena,lenb,lenc,i,j,k,x;
	string s,ss;
	cin>>s;
	cin>>ss;
	a[0]=s.size();
	b[0]=ss.size();
	if(s.size()<ss.size()||(s.size()==ss.size()&&s<ss)){
		cout<<0<<endl<<s<<endl;
		return;
	}
	fe(i,1,a[0])a[i]=s[a[0]-i]-'0';
	fe(i,1,b[0])b[i]=ss[b[0]-i]-'0';
	c[0]=a[0]-b[0]+1;
	de(i,c[0],1){
		memset(tmp,0,sizeof(tmp));
		fe(j,1,b[0])tmp[j+i-1]=b[j];
		tmp[0]=b[0]+i-1;
		while(compare()>=0){//减法模拟,都是a数组与tmp的比较
			c[i]++;
			jian();
		}
	}
	while(c[0]>0&&c[c[0]]==0)c[0]--;
	if(c[0]==0){
		cout<<0<<endl;
	}else{
		de(i,c[0],1)cout<<c[i];//c是最后的商
		cout<<endl;
	}
	if(a[0]==0){
		cout<<0<<endl;
	}else{
		de(i,a[0],1)cout<<a[i];//a是最后的余数
		cout<<endl;
	}
	return ;
}

E:凢凢的烦恼

题目传送门

题意:给你两个数,a和b,求(a!)%(M),(b!)%(M),M=97126719690。

思路:我们这里有两种思路,首先我们看到这道题的数据之大,我们就可以猜测这道题必定不会是暴力可以做到的,但是我们又发现这题这么简单,会不会是我们想复杂了呢?特别是这种我们一看输出特定值的题,一般情况都会是有规律的(除非出题人是狗)那么我们就先暴力暴力

    int x,y;int da1=1,da2=1;
    while(1){
    	cin>>x;
		for(i=1;i<=x;i++){
			da1*=i;
			da1%=M;
		}
		cout<<da1<<endl;
	}

然后我们就会发现,到达某个值后,后面的da1全为0,这个时候我们仔细找找就会发现那个值为1033

这道题的答案也就呼之欲出啦(是不是很简单啦(๑•̀ㅂ•́)و✧)

    int i,j;
	int x,y;int da1=1,da2=1;
	cin>>x>>y;
	if(x>1033)da1=0;
	else{
		for(i=1;i<=x;i++){
			da1*=i;
			da1%=pi;
		}
	}
	if(y>1033)da2=0;
	else{
		for(i=1;i<=y;i++){
			da2*=i;
			da2%=pi;
		}
	}
	if(da1>da2)cout<<"@@"<<endl;
	else if(da1<da2)cout<<"heilong"<<endl;
	else cout<<"kewu"<<endl;

我的天哪我们这么快就写到了F题了吗?w(゚Д゚)w

F:圈圈的烦恼

题目传送门

题意:这道题嘛,咱们抽象抽象,最后就可以看成在一段序列中,找到最长上升子序列,只不过呢,因为这次的数据比较大,我们不可能再用原来(n^{2})的办法了,5e5的数据必定会TLE的,因此我们需要想一想如何将时间复杂度压缩到(n)到(nlogn)不然就要凉凉︿( ̄︶ ̄)︿

思路:那么应该是跑一遍就应该要出答案,首先明确一个点,我们要知道,要想上升子序列最长,那么每一跳的高度要尽可能的低。

此时我们创建一个dp[len]数组

len是现在我们得到的最长上升子序列的长度

然后就是不断的去维护这个dp数组了。

当前a[i]>dp[len]时,说明这个a[i]满足条件,那么我们这时更新数组,dp[++len]=a[i]

不然,我们就在dp数组中找到一个dp[j],使得a[i]<dp[j]<=a[i+1],此时我们更新数组dp[j]=a[i+1]

第一步我相信大家应该都理解了,我们来看第二步,首先现在的最长子序列的长度是已经确定了的,必定长为len,那么这个时候,如果能够找到这一个j,更新dp数组,使得dp数组一直保持着线性的性质,方便我们查找,这个时候你会问,那我更改dp[len]值怎么办,那我们既然能够使得我dp[len]>a[i],那么我就是满足最长上升子序列的性质,那么就可以更改,这又有什么关系呢?

举个例子┗|`O′|┛ 嗷~~

1 3 8 5 7

我们发现8能够在3后面,5也能在3后面,那为什么我们不让5在3的后面呢?

那么现在我们来瞅瞅代码:

    cin>>n;
	fe(i,1,n)cin>>a[i];
	len=1;dp[len]=a[1];
	fe(i,2,n){
		if(a[i]>dp[len])dp[++len]=a[i];
		else {
			da1=lb(dp+1,dp+len+1,a[i])-dp;//二分查找,减少时间复杂度,阔以自己写二分哦
			dp[da1]=a[i];                //我用的自带的二分
		}
	}
	cout<<len<<endl;

是不是很吃惊,是不是感觉很惊讶o(*^@^*)o,没办法有些题,想到了就很简单,想不到它也很简单,只不过做不来而已~~( ﹁ ﹁ ) ~~~

好吧今天的题解就到这里,期待下一次的相遇(づ ̄3 ̄)づ╭❤~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值