——暨校GDKOI集训赛
T1: 数字统计
给出N个正整数,其中有且只有有一个数字出现超过n/2次,求这个数字
Input
第一行为N,接下来一行,有N个正整数。
Output
出现n/2次的数字。
Sample Input
5
1 2 3 3 3
Sample Input
3
Hint
20%:
n≤1000
40%:
n≤10000
60%:
n≤10000000
100%:
n≤50000000,ai≤2147483647
经亲自查看数据得,最大的输入文件30M。
Solution
出题人怒调戏众人:标程只有10行!
于是因为数据水一堆人骗了接近满分让出题人颜面扫地。
而且好像标程在本地测得40分,原因超时。。我开了快速读入只有60分。。
还是暴力大法好,哈希保平安!
显然只有
O(n)
的方法,考虑先置答案为第一个数字,然后扫一遍,如果
ai≠ai−1
,那么
count++
,否则
count−−
,如果
count=0
,那么置答案为下一个数字即可。
然而标程怒跪并不贴程序。。
T2: 翻骰子
我们有2*n个骰子,分成两行放置(lz注:设为a和b两个向量)。有一种操作,是将上下两个骰子翻转过来(lz注:交换 ai,bi ),我们想知道,当第一行的和减去第二行的和(lz注:取绝对值)最小时,需要翻转的最小次数。
Input
第一行一个正整数n
接下来n行,每行两个整数,分别表示第i列的上下两个骰子的点数(lz注:即
1≤ai,bi≤6
)。
Output
一行一个整数,最少的翻转次数。
Sample Input
4
6 1
1 5
1 3
1 2
Sample Output
1
Sample Explanation
将最后一列的骰子翻转即可。
Hint
20%:
n≤10
50%:
n≤100
100%:
n≤1000
Solution
考虑表示一下答案,
如果交换了第 i 列,那么
令 x=sumA−sumB,ci=2(ai−bi) ,那么
使ans最小,那么就选出来的某些 ci 的和尽可能地接近 x ,似乎是个背包问题?
搜索dp皆可解决之。
另外纯dp也可。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;i++)
const int N = 1005, Maxx = 10005, inf = 0x7f7f7f7f;
int i,j,k,a,b,n,tc=0;
int g[N], f[N][N];
int g0, ma, da = inf, D = inf;
void getmin(int &a, int b) { if (a > b) a = b; }
int main() {
memset(f, 127, sizeof f);
scanf("%d",&n);
FOR(i,1,n) scanf("%d%d", &a, &b), g[i] = a - b;
g0 = 5 * n; ma = n * 10;
f[0][g0] = 0;
int i, j;
FOR(i,1,n) FOR(j,0,ma) if (f[i - 1][j] != inf) {
getmin(f[i][j + g[i]], f[i - 1][j]);
getmin(f[i][j - g[i]], f[i - 1][j] + 1);
}
FOR(j,0,ma) if (f[n][j] != inf)
if (abs(j - g0) < D) {
D = abs(j - g0);
da = f[n][j];
} else if (abs(j - g0) == D)
getmin(da, f[n][j]);
printf("%d",da);
return 0;
}
T3: 糖果传递
详见:http://blog.csdn.net/huanghongxun/article/details/50675569
T4: N^2皇后问题
给定N,求N^2皇后问题的一组可行解。
Input
一个N(1\leq N\leq 8)
Output
Sample Input
1
Sample Output
1
Solution
说实话考试时没想到
n2
有啥神奇特征,于是自信写随机。。
好像机房有同学是dfs过的,因为发现大多数的皇后都是在上一行皇后的右边2格位置(一个马的距离),优选那个位置继续dfs,然后打表。好像这样dfs特别快。。
正解好神奇。。
发现实际上。。N^2皇后就相当于一个N皇后问题,然后在放了皇后的地方在开一个N*N的棋盘,小棋盘结果N皇后问题的解。因此问题转化为求N皇后问题的解。于是N^3,N^4以此类推。
只给随机的程序。。
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
#define FOR(i,j,k) for(i=j;i<=k;i++)
#define rep(i,j,k) for(i=j;i<k;i++)
int random(int x) {
return (int)(((double) rand()) / RAND_MAX * x);
}
int c[8192], n;
void init() {
int i, j;
rep(i,0,n) c[i] = i;
rep(i,0,n) {
j = random(n);
swap(c[j], c[n-j-1]);
}
}
int h(vector<int> &l) {
int i, j;
l.clear();
rep(i,0,n) rep(j,i+1,n)
if (c[j] == c[i] + j - i || c[j] == c[i] - j + i)
l.push_back(j);
return l.size();
}
int exc(int j1, int j2, vector<int> &l) {
vector<int> nl;
swap(c[j1], c[j2]);
h(nl);
if (nl.size() > l.size()) swap(c[j1], c[j2]);
else l = nl;
return nl.size();
}
int next(vector<int> &l) {
int ls = l.size(), j1 = -1, j2 = -1, i, e;
if (l.size() == 1)
rep(i,0,n) if (i != l[0])
if (!exc(l[0], i, l))
return 0;
do {
j1 = random(n);
do j2 = random(n); while (j1 == j2);
e = exc(j1, j2, l);
} while(e > ls);
return e;
}
void solve() {
vector<int> l;
int step, cl, tr, i;
for (tr = 0; tr < n * n; ++tr) {
l.clear(); step = 0;
srand(time(0) + tr * cl);
init();
for (cl = h(l); cl && step < n * n; cl = next(l), ++step);
if (!cl) {
rep(i,0,n) printf("%d\n", c[i] + 1);
return;
}
}
}
int main() {
while (scanf("%d", &n) != EOF) {
n *= n;
solve();
}
return 0;
}