Codeforces Round 957 (Div. 3)

A. Only Pluses

暴力题

不难发现数据范围很小,直接暴力计算最大值即可 

或者每次给最小的 ++ ,用最小堆来维护 

void Rainbow_()
{
	int a,b,c;
	cin >> a >> b >> c;
	
	priority_queue<int, vector<int>, greater<int> > q;
	q.push(a);q.push(b);q.push(c);
	
	int cnt = 5;
	
	while( cnt ) {
		int w = q.top();
		w ++ ;
		q.pop();
		q.push(w);
		cnt -- ;
	}
	
	a = q.top();q.pop();
	b = q.top();q.pop();
	c = q.top();q.pop();
	
	cout << a * b * c << '\n';
	
	return ;
}

or

void Rainbow_()
{
	int a,b,c;
	cin >> a >> b >> c;
	
	int ans = -1;
	
	for(int i = 0; i <= 5; i ++ ) {
		for(int j = 0; i + j <= 5; j ++ ) {
			for(int k = 0 ; i + j + k <= 5; k ++ ) {
				ans = max( (a +i) * (b + j) * ( c + k ) , ans ); 
			}
		}
	}
	cout << ans << '\n';
	return ;
}

B. Angry Monk

英语阅读能力测试题

贪心的把所有移动到最大的

void Rainbow_()
{
    int n,k;
    cin >> n >> k;

	vector<int> a(k);
	for(int i = 0 ; i < k ; i ++ ) {
		cin >> a[i];
	}
	sort(a.begin(),a.end());
	int ans = 0;
	
	for(int i = 0 ; i < k - 1; i ++ ) {
		ans += a[i] * 2 - 1;
	}
	
	cout << ans << '\n';
	return ;
}

C. Gorilla and Permutation\

一个简单构造题

答案分为三段 , 我们需要查看每段的贡献.

g数组在小于等于 m 的时候有贡献 ,f数组在大于等于k的时候有贡献,又因为 m < k 所以我们没有办法使得两个数组同时出现贡献,所以我们贪心的选择更大的贡献,也就是

区间1 : 先从大到小输出最大的k个数字

区间2: m ~ k这个区间里面我们可以任意输出 

区间3: 1~m的区间我们从小到大输出前m个字

如果直接按照这三个区间写,会出现一些边界的问题,我们可以合并前两个循环来实现

自己探究为什么写三个循环会出现边界问题捏

void Rainbow_()
{
    int n,m,k;
    cin >> n >> m >> k;
    
    for(int i = n; i > m; i -- ) {
    	cout << i << ' ';
    }
    
    for(int i = 1; i <= m; i ++ ) {
    	cout << i << ' ';
    }
    cout << '\n';
    return ;
}

D. Test of Love

典型的 DP 

我们用 dp[i]来表示 游到第 i 个位置所需要的最小游泳距离

不难得到 转移方程

dp[i] = min(dp[i],dp[i - j]) , s[i -j] == L and 1 \leq j\leq m

dp[i] = min(dp[i],dp[i - 1]) ,s[i - 1] == W

dp[i] = 0 ,s[i] = C

把这三个式子写出来就AC了

void Rainbow_()
{
    int n,m,k;
    cin >> n >> m >> k;
    
    string s;
    cin >> s;
    s = 'L' + s + 'L';

    vector<int> dp(n + 2,INF);

    dp[0] = 0;
    
    for(int i = 1; i <= n + 1 ; i ++ ) {
    	if (s[i] == 'C' ) {
    		continue ;
    	} 
    	if(s[i - 1] == 'W' ) {
    		dp[i] = min(dp[i],dp[i - 1] + 1);
    	}
    	
    	for(int j = 1; j <= m; j ++ ) {
    		if( i < j ) {
    			break ;
    		}
    		if (s[i - j] == 'L' ) {
    			dp[i] = min(dp[i] , dp[i - j]);
    		}
    	}
    }
    
    if( dp[n + 1] <= k ) {
    	cout << "YES\n";
    } else {
    	cout << "NO\n";
    }
    
    return ;
}

E. Novice's Mistake

如果枚举再范围内的所有情况那么必定超时 , 所以我们观察题目

首先题目要求 S 非空, 所以 n *a - b < n * a <= 1e7 必定为真 , 所以最后的结果最多7位

所以 b 的范围就确定为 [len(a) * a - 7 , len(a) * a - 1]

直接枚举 a 和 b的值在模拟即可 

void Rainbow_()
{
    int n;
    cin >> n;
    string s = to_string(n);
    
    int t = 1;int len = s.size();
    for(int i = 0 ; i < len ; i ++ ) {
    	t *= 10;
    }
    
    vector<int> tmp;
    for(int i = 0 ; i < len ; i ++ ) {
    	tmp.pb(s[i] - '0');
    }
    
    vector< pair<int,int> > ans;
    
    for(int a = 1; a <= 1e4; a ++ ) {
    	for(int b = max( 1ll , len * a - 7) ; b <= len * a - 1; b ++ ) {
    		int res1 = n * a - b;
    		int res2 = 0;
    		int k = len * a  - b;
    		while( k > 0 ) {
    			if( k >= len ) {
    				k -= len ;
    				res2 = res2 * t + n;
    			} else {
    				for(int o = 0 ; o < k ; o ++ ) {
    					res2 = res2 * 10ll + tmp[o];
    				}
    				k = 0;
    			}
    		}
    		if(res1 == res2 ) {
    			ans.pb({a,b});
    		}
    	}
    }
    
    cout << (int) (ans.size() ) << '\n';
    for(auto it : ans ) {
    	cout << it.x << ' ' << it.y << '\n';
    }
    
	return ;
}

F. Valuable Cards

最佳策略就是从头开始尽可能的取,直到取第 ai 个的时候不符合条件了 , 便回退一格 , 另开始取新的一段 , 用一个 f 数组 来维护当前是否可以凑出 i 

void solve()
{
	cin>>n>>x;
	map<int,int>dp;
	for(int i=1;i<=n;i++)cin>>a[i];
	vector<int>f;
	for(int i=1;i<=x/i;i++)
	if(x%i==0)
	{
		f.push_back(i);
		if(i!=x/i)f.push_back(x/i);
	}
	dp[1]=1;
	sort(f.begin(),f.end());
	reverse(f.begin(),f.end());
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int y:f)if(dp[y])dp[y*a[i]]=1;
		bool ok=false;
		if(dp[x])
		{
			//cout<<i<<endl;
			ans++;
			i--;
			dp.clear();
			dp[1]=1;
		}
	}
	cout<<ans+1<<endl;
}

另一个简单的方法,我们可以用set来维护 (前提数学条件 : 一个数 x 能被最多logx 个数除完。)

所以我们可以直接枚举,用 set 存储当前要选的一段区间中所有能区间中一些数相乘得到 x 的数。如果后面遇到的 set 中的某个数,则需要从这个开始划分一个新的区间。

void Rainbow_()
{
    int n,x;
    cin >> n >> x;
    
	set<int> s;
	int cnt = 0;
	
	for(int i = 1; i <= n; i ++ ) {
		int a;cin >> a;
		if( s.find(a) != s.end() ) {
			cnt ++;
			s.clear();
		}
		
		auto tmp = s;
		for(auto c : tmp) {
			if( c % a == 0 ) {
				s.insert(c / a);
			}
		}
		
		if( x % a == 0 ) {
			s.insert( x / a );
		}
	}

	cout << cnt + 1 << '\n';
	return ;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值