[codeforces 1350B] Orac and Models 约数+深搜dfs

Codeforces Round #641 (Div. 2)   参与排名人数11937

[codeforces 1350B]   Orac and Models   约数+深搜dfs

总目录详见https://blog.csdn.net/mrcrack/article/details/103564004

在线测评地址http://codeforces.com/contest/1350/problem/B

ProblemLangVerdictTimeMemory
B - Orac and Models GNU C++17Accepted452 ms24400 KB

没想到第二题,就有如此难度,感觉此题难度介于AtCoder的(ABC比赛)的C题与D题之间。

基本思路,从位置最大值开始,枚举相应约数,看是否符合题意,若符合,则参与计数。

100000的约数,30个不到,故,找到1-100000的所有约数100000*30=3*10^6不超时,事先算出所有约数,

再具体根据约数,找到较小位置的数据,看是否符合题意,能否参与计数。

样例模拟如下

4
5 3 4 6

位置1 2 3 4
数值5 3 4 6

从位置4开始
a[4]=6>a[2]=3 计数2
a[4]=6>a[1]=5 计数2

a[3]=4<a[1]=5
a[2]=3<a[1]=5
最大计数值是2 


7
1 4 2 3 6 4 9
位置1 2 3 4 5 6 7
数值1 4 2 3 6 4 9
a[7]=9>a[1]=1 计数2
a[6]=4>a[3]=2>a[1]=1 计数3
a[6]=4>a[1]=1 计数2
a[5]=6>a[1]=1 计数2
a[4]=3>a[1]=2 计数2
a[3]=2>a[1]=1 计数2
a[2]=4>a[1]=1 计数2
最大计数值是3    

5
5 4 3 2 1
位置1 2 3 4 5
数值5 4 3 2 1
最大计数值是1 


1
9
最大计数值是1 

AC代码如下

#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
int a[maxn],b[maxn][50],bn[maxn],tot=0,cnt[maxn];
void dfs(int step,int now){//step记录当前步数,now表示当前位置的值
	int i,c;
	for(i=1;i<=bn[now];i++){
		c=b[now][i];//c是now的约数
		if(a[now]>a[c])cnt[step]=cnt[step-1]+1,tot=max(tot,cnt[step]),dfs(step+1,c);//符合题意,计数cnt[]加1
	}
}
int main(){
	int t,n,i,j,pre;
	for(i=1;i<=100000;i++)
		for(j=1;j*j<=i;j++)
			if(i%j==0){
				bn[i]++;
				b[i][bn[i]]=j;//表示i在bn[i]处的约数是j
				if(i/j!=j)bn[i]++,b[i][bn[i]]=i/j;//bn[i]统计i的约数个数
			}
	scanf("%d",&t);
	while(t--){
		tot=1;
		scanf("%d",&n);
		for(i=1;i<=n;i++)scanf("%d",&a[i]);
		for(i=n;i>=1;i--)
			cnt[0]=1,dfs(1,i);
		printf("%d\n",tot);				
	}
	return 0;
}

方法二:神奇的动归dp,像最长上升子序列

ProblemLangVerdictTimeMemory
B - Orac and Models GNU C++17Accepted62 ms4400 KB

样例数据处理过程如下

i=1 j=1
i=1 j=2
i=1 j=3
i=1 j=4
i=2 j=2
i=2 j=4
i=3 j=3
i=4 j=4
2
i=1 j=1
i=1 j=2
i=1 j=3
i=1 j=4
i=1 j=5
i=1 j=6
i=1 j=7
i=2 j=2
i=2 j=4
i=2 j=6
i=3 j=3
i=3 j=6
i=4 j=4
i=5 j=5
i=6 j=6
i=7 j=7
3
i=1 j=1
i=1 j=2
i=1 j=3
i=1 j=4
i=1 j=5
i=2 j=2
i=2 j=4
i=3 j=3
i=4 j=4
i=5 j=5
1
i=1 j=1
1

AC代码如下

#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
int a[maxn],dp[maxn],ans;
int main(){
	int t,n,i,j;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(i=1;i<=n;i++)scanf("%d",&a[i]);
		for(i=1;i<=n;i++)dp[i]=1;
		ans=0;
		for(i=1;i<=n;i++)//i是约数,约数逐渐变大
			for(j=i;j<=n;j+=i)//j%i==0
				if(a[i]<a[j])dp[j]=max(dp[j],dp[i]+1);
		for(i=1;i<=n;i++)ans=max(ans,dp[i]);
		printf("%d\n",ans);
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值