SRM 496 DIV 1 总结

250p:大水题,给你一幅图,水平可以连续染色red,垂直可以连续染色blue,水平垂直都有染色就是green,问从空白图到给你的图最少需要多少次染色。对于red和blue分开考虑就可以了,也可以先把green转换为red或者blue,然后贪心搞。


500p:令人蛋疼的题,弄了一天,往dp上想破了脑子最后居然算法还是错的,最后参考了Soooooooo大神的解题思路才搞出来  http://hi.baidu.com/ryannnnnnnn/item/76af1d161b61b0e964eabf29



题意 :在数轴上有一些球,这里简化为点,他们都以相等的速度或左或右的移动,给你两张图,一张是点原来的位置,另一张是移动后的位置,问有多少种方案使得第一张图的点对应到第二张的图的点,注意第二张图可以加入新的点。

由此,假设第一张图为A,第二张为B,首先对于他们都要排好序。

对于A中的点在B中最多对应两个点,而且A中的两个点如果在B中对应一个点,一定是A[i]+dis = A[j]-dis,首先我们可以计算出所有可能的速度,然后对于每一个速度计算方案数相加即可。

对于A中未访问过的点,向B拓展一条链,比如B1-A1-B2-A2-..-Bk-Ak-B(k+1),

举个例子 假设A中有1 3 5 7 10      B中有2 4 6 9 12

对于速度为1的情况,从A中第一个点开始拓展可以得到

1    3    5    7

   2    4    6

这条链就是a[0] - b[0] - a[1] - b[1] - a[2] - b[2] - a[3]


有了的思路,自己心里也就很清楚了,毕竟搞了一天了,印象还是很深刻的。也就是说对于某个速度dis,我们要找到所有的链,而所有的链都是互不相干的,那么所有链的情况数相乘就是这个dis的所有情况数,对于上下点相等的链,只有一种配对方法,对于下面点比上面多一的,有下面点数中配对方法,上面点比下面多一的显然就不可能配对,这几种情况在图上画一下就很清楚了。


#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <string.h>
#include <cstdlib>
#include <ctime>
#define LL long long

using namespace std;

class OneDimensionalBalls {
public:
	LL countValidGuesses(vector <int>, vector <int>);
};

int juli[55];
bool vis[55];
LL OneDimensionalBalls::countValidGuesses(vector <int> fp, vector <int> sp) {
	int i, j;
	sort(fp.begin(), fp.end());
	int num = 0;
	printf("%d\n", sp.size());
	for(i = 0;i < sp.size(); i++) {
		int dis = abs(sp[i] - fp[0]);
		if(dis == 0)	continue;
		for(j = 1;j < fp.size(); j++) {
			int zai = fp[j] - dis;
			int x = lower_bound(sp.begin(), sp.end(), zai) - sp.begin();
			if(x < sp.size() && sp[x] == zai)	continue;
			zai = fp[j] + dis;
			x = lower_bound(sp.begin(), sp.end(), zai) - sp.begin();
			if(x < sp.size() && sp[x] == zai)	continue;
			break;
		}
		if(j == fp.size())	juli[num++] = dis ;
	}
	LL ans = 0;
	if(num == 0)	return ans;
	sort(juli, juli+num);
	int k = 1;
	for(i = 1;i < num; i++) if(juli[i] != juli[i-1])
		juli[k++] = juli[i];
	num = k;
	for(i = 0;i < num; i++) {
		memset(vis, 0, sizeof(vis));
		LL mul = 1;
		for(j = 0;j < fp.size(); j++) {
			if(vis[j])	continue;
			vis[j] = 1;
			int up = 1;
			int down = 0;
			int x = fp[j]-juli[i];
			int pos = lower_bound(sp.begin(), sp.end(), x) - sp.begin();
			if(pos < sp.size() && sp[pos] == x)
				down++;
			int to = j;
			while(1) {
				x = fp[to]+juli[i];
				pos = lower_bound(sp.begin(), sp.end(), x) - sp.begin();
				if(pos < sp.size() && sp[pos] == x) {
					down++;
				}
				else break;
				x = fp[to]+2*juli[i];
				pos = lower_bound(fp.begin(), fp.end(), x) - fp.begin();
				if(pos < fp.size() && fp[pos] == x) {
					up++;
					vis[pos] = 1;
					to = pos;
				}
				else break;
			}
			if(up == down-1)
				mul = down*mul;
			else if(up == down+1)
				mul = 0;
		}
		ans += mul;
	}
	printf("%lld\n", ans);
	return ans;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值