uva 的 3 道水题

好吧我发现我走了一些弯路,两本白皮书还没看完就弄其他的去了,其实其他的也没怎么弄。现在回来补白皮书。

uva 340 猜数字游戏。

给你一个源序列(由数字0 ~ 9组成),再给你多个目标序列。让你统计两个数A和B,A是在源序列和目的序列里都出现了且位置正确的,B是在两个序列中都出现了,但是位置不正确的。

例如

1 3 5 5

1 1 2 3  A = 1, B = 1;(因为数字1在源串和目的串中都出现了且位置相同(0位置),而数字3在源串和目的串中都出现了,但是位置不同(分别是1 和 3))。

题意大概是这样(不要管1位置的数字1,因为已经有0位置的数字1满足A情况)


分析:A很好求出,但是B的话有点麻烦(而且要剔除A中的情况)。

书上的分析是:直接统计就可以得到A,为了求B,对于每个数字(1 ~ 9),统计二者出现的次数 c1 和 c2,则 min(c1, c2)就是该数字对B的贡献,最后输出的时候要减去A的部分。

的确,数据范围特别小,只是从1 ~ 9,所以这种做法是很好的(O(9 * n))。而如果要逐个比较的话,复杂度是O(n^2)并且还很容易重复计算。汝佳老师的解法的确简单。

(对了,这段时间做题目我一直尝试丢开IDE而用gvim,尝试不要单步调试而采用输出调试。。不知道有没有好处)

/*************************************************************************
    > File Name: main.cpp
    > Author: Triose
    > Mail: Triose@163.com 
    > Created Time: 2016/4/13 星期三 下午 9:58:17
 ************************************************************************/
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define inf 0x3f3f3f3f
#define rep(i,a) for((i)=0; i<(a);(i)++)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define LL __int64
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }
template<class T> inline T Min(T a, T b) { return a<b ? a : b; }
template<class T> inline T Max(T a, T b) { return a>b ? a : b; }
int n, m;
#define N 1010
int souce[N];
int aim[N];
int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
//	freopen("Out.txt", "w", stdout);
#endif
	int k = 0;
	while(sf(n) && n) {
		for(int i = 0; i < n; i++) {
			sf(souce[i]);
		}
		printf("Game %d:\n", ++k);
		for(; ;) {
			int a = 0, b = 0;
			for(int i = 0; i < n; i++) {
				sf(aim[i]);
				if(aim[i] == souce[i])
					a++;
			}
			if(!aim[0])
				break;
			int tmps = 0, tmpa = 0;
			for(int i = 1; i < 10; i++) {
				for(int j = 0; j < n; j++) {
					if(souce[j] == i)
						tmps++;
					if(aim[j] == i)
						tmpa++;
				}
				b += Min(tmps, tmpa);
				tmps = 0;
				tmpa = 0;
			//	pf(b);
			}
			printf("    (%d,%d)\n",a,b - a);
		}
	}
	return 0;
}


第二题, uva 1583

意思是x + (x的各位数之和) = y,那么x就是y的生成元。现在给你一个n,求它的最小生成元。1<=n <= 1e+5

分析一下就可以发现x < y,求最小生成元的过程可以采用i 从 [1, n)的循环求出,一旦满足条件输出结束。

但是这样会很慢,而题目的数据范围不是很大,数组能存下。所以可以采用O(N)的预处理和O(1)查询的方法。

但是我一开始脑子有点问题是用的O(N)的预处理和O(n)的查询。。。。不过也过了(ans [i] = i + getsum(i),意思是i是ans[i]的最小生成元,然后输入n遍历输出就行了)

后来脑子一抽发现自己神经病,既然ans[i] 能等于 i + getsum(i),为什么ans[i + getsum(i)]不能等于 i呢,这样就是O(1)查询

后来又wa了一发因为求出来的生成元并不是最小的。。。。因为后来的覆盖了。。。所以加上一句,如果ans[i] != 0 就不做任何操作。

/*************************************************************************
    > File Name: main.cpp
    > Author: Triose
    > Mail: Triose@163.com 
    > Created Time: 2016/4/13 星期三 下午 10:49:15
 ************************************************************************/

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define inf 0x3f3f3f3f
#define rep(i,a) for((i)=0; i<(a);(i)++)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define LL __int64
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }
template<class T> inline T Min(T a, T b) { return a<b ? a : b; }
template<class T> inline T Max(T a, T b) { return a>b ? a : b; }
int n, m;
#define N 100010
int ans[N];
int getans(int i) {
	int tmp = 0;
	while(i) {
		tmp += i % 10;
		i /= 10;
	}
	return tmp;
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("Out.txt", "w", stdout);
#endif
	mem(ans,0);
	for(int i = 1; i < N; i++) {
		int tmp = i + getans(i);
		if(!ans[tmp]) 
			ans[tmp] = i;
	}
	/*
	for(int i = 0; i < 20; i++) {
		pf(ans[i]);
	}
	*/
	int t;
	sf(t);
	while(t--) {
		sf(n);
		pf(ans[n]);
	}
	return 0;
}


uva 1584

意思是给定一个AGCT四个字母组成的字符串(环状),让你输出从某个位置开始的字典序最小的字符串。

分析:我一开始想,这尼玛加权求个sum然后如果sum< sum0就让sum0等于sum然后记录位置最后从pos开始输出就行了吗。。。后来一想sum += str[i] - 'A', sum *= 10就行了。。。后来一想,10 ^100没哪个类型能存下。。放弃。。不过当然没放弃,我想AGCT四个字母尼玛我改成4进制的加权总行了吧?果然还是存不下。。我一想 4^100次方也挺大,不行。。。。后来还是看了书上的方法。。。真是该剁手。。贴代码吧

/*************************************************************************
    > File Name: main.cpp
    > Author: Triose
    > Mail: Triose@163.com 
    > Created Time: 2016/4/14 星期四 上午 10:34:12
 ************************************************************************/

#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<map>
#include<set>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define inf 0x3f3f3f3f
#define rep(i,a) for((i)=0; i<(a);(i)++)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define enter putchar(10)
#define LL __int64
const double PI = acos(-1.0);
const double E = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a%b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b)*b; }
template<class T> inline T Min(T a, T b) { return a<b ? a : b; }
template<class T> inline T Max(T a, T b) { return a>b ? a : b; }
int n, m;
#define N 110
char str[N];
int ans;
int len;
int pos;
int cmp(int u, int v) {
	for(int i = 0; i < len; i++) {
		if(str[(u + i) % len] != str[(v + i) % len]) 
			return str[(u + i) % len] > str[(v + i) % len];
	}
	return 0;
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
//	freopen("Out.txt", "w", stdout);
#endif
	int _;
	sf(_);
	while(_--) {
		sfs(str);
		pos = 0;
		ans = 0;
		len = strlen(str);
		for(int i = 1; i < len; i++) {
			if(cmp(ans, i)) {
				ans = i;
			}
		}
		for(int i = 0 ; i < len; i++) {
			putchar(str[(ans + i) % len]);
		}
		enter;
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值