A - Lights Against Dudely
题意
Harry要闯过一个迷宫,他有一些灯,把灯放在(x,y)
位置,它会照亮(x, y) (x-1, y) (x, y+1)
三个位置。并且Harry有一盏神奇的灯,它的方向可以旋转 0°, 90°, 180° 或270°。现在,Harry不能点亮#
位置,并且要点亮所有的.
位置。问Harry最少要用多少盏灯。
思路
一年前就做过这道题,当时用的状压dp,这次重新看到这题,却发现只需要暴力枚举就行了。题目里.
的点比较少,二进制枚举哪些点放了普通的灯。然后再判断是否要用上那盏特殊的灯。就是这样乱搞喽,代码可能会复杂一点。
code
#include <bits/stdc++.h>
using namespace std;
const int INF = 999999999;
int n, m;
char s[205][205];
int dp[(1<<15)+5];
struct Point {
int x, y;
Point(){}
Point(int _x, int _y) {
x = _x;
y = _y;
}
}p[20];
int _c = 0;
int cc[205][205];
void init () {
_c = 0;
memset(cc, -1, sizeof cc);
for (int i=0; i<n; i++) {
for (int j=0; j<m; j++) {
if (s[i][j] == '.') {
cc[i][j] = _c;
p[_c++] = Point(i, j);
}
}
}
}
bool judge (int _x, int _y) {
if (_x >= 0 && _x < n && _y >= 0 && _y < m && s[_x][_y] == '#') {
return false;
} else return true;
}
int X[] = {-1, 0, 1, 0, -1};
int Y[] = {0, 1, 0, -1, 0};
int ans, res;
void _solve (int _s) {
bool li[20] = {0};
int _cnt = 0;
for (int i=0; i<_c; i++) {
if (!(_s & (1 << i))) continue;
_cnt ++;
int _x, _y;
li[i] = true;
_x = p[i].x;
_y = p[i].y+1;
if (_x < n && _x >= 0 && _y >= 0 && _y < m) {
if (s[_x][_y] == '.') {
li[cc[_x][_y]] = true;
} else return ;
}
_x = p[i].x-1;
_y = p[i].y;
if (_x < n && _x >= 0 && _y >= 0 && _y < m) {
if (s[_x][_y] == '.') {
li[cc[_x][_y]] = true;
} else return ;
}
}
int lighted = 0;
for (int i=0; i<_c; i++) {
if (li[i] == true) lighted ++;
}
if (lighted == _c) {ans = min (ans, _cnt); return ;}
if (lighted + 3 < _c) return ;
for (int i=0; i<_c; i++) {
if (_s & (1 << i)) continue;
// i was not put light
for (int j=0; j<4; j++) {
int tmp = lighted;
if (li[i] == false) tmp++;
int x0 = p[i].x + X[j];
int y0 = p[i].y + Y[j];
if (x0 < n && x0 >= 0 && y0 < m && y0 >= 0) {
if (s[x0][y0] == '.') {
if (li[cc[x0][y0]] == false) tmp++;
} else continue ;
}
int x1 = p[i].x + X[j+1];
int y1 = p[i].y + Y[j+1];
if (x1 < n && x1 >= 0 && y1 < m && y1 >= 0) {
if (s[x1][y1] == '.') {
if (li[cc[x1][y1]] == false) tmp++;
} else continue ;
}
if (tmp == _c) {
// cout << "QAQ" << endl;
ans = min(ans, _cnt+1);
}
}
}
}
int main () {
for (;scanf("%d%d", &n, &m) == 2;) {
if (n == 0 && m == 0) break;
for (int i=0; i<n; i++) {
scanf ("%s", s[i]);
}
init ();
ans = INF;
for (int s=0; s<(1 << _c); s++) {
_solve(s);
}
if (ans == INF) cout << -1 << endl;
else cout << ans << endl;
}
return 0;
}
B - Stealing Harry Potter’s Precious
题意
迷宫里有n
礼物(n<4)
,问收集所有的礼物要的最小步数。不能收集齐则输出-1
.
思路
楚神的题,bfs呗,能重复走的情况仅当收集到了更多的礼物。
code
/*******************************************************************************
*** problem ID : _B.cpp
*** create time : Sat Oct 31 12:13:25 2015
*** author name : nndxy
*** author blog : http://blog.csdn.net/jhgkjhg_ugtdk77
*** author motto: never loose enthusiasm for life, life is to keep on fighting!
*******************************************************************************/
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <vector>
#include <cctype>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define end() return 0
const int maxn = 100 + 5;
int N, M;
char str[maxn][maxn];
int K, X[6], Y[6], sx, sy;
bool ok;
void input(){
memset(str, '\0', sizeof(str));
for(int i = 0; i < N; i++){
scanf("%s", str[i]);
for(int j = 0; j < M; j++){
if(str[i][j] == '@'){
sx = i;
sy = j;
}
}
}
scanf("%d", &K);
for(int i = 0; i < K; i++){
scanf("%d%d", &X[i], &Y[i]);
}
}
struct P
{
int x;
int y;
int key;
int step;
P(){}
P(int _x, int _y, int _key, int _step) : x(_x), y(_y), key(_key), step(_step) {}
friend bool operator<(P a, P b) { return a.step > b.step; }
};
int xx[] = {0, 1, 0, -1};
int yy[] = {1, 0, -1, 0};
int bfs(){
priority_queue <P> q;
bool vis[maxn][maxn][25];
memset(vis, false, sizeof(vis));
q.push(P(sx, sy, 0, 0));
vis[sx][sy][0] = true;
int sumkey = (1 << K) - 1;
while(!q.empty()){
P p = q.top(), w; q.pop();
if(p.key == sumkey) return p.step;
for(int i = 0; i < 4; i++){
w.x = p.x + xx[i];
w.y = p.y + yy[i];
w.step = p.step + 1;
w.key = p.key;
if(w.x >= 0 && w.x < N && w.y >= 0 && w.y < M && str[w.x][w.y] != '#'){
for(int j = 0; j < K; j++){
if(w.x == X[j] - 1 && w.y == Y[j] - 1){
int key = (1 << j);
if(!(w.key & key)){
w.key += key;
vis[w.x][w.y][w.key] = true;
q.push(w);
}
break;
}
}
if(!vis[w.x][w.y][w.key]){
vis[w.x][w.y][w.key] = true;
q.push(w);
}
}
}
}return -1;
}
void solve(){
printf("%d\n", bfs());
}
int main(){
while(scanf("%d%d", &N, &M) != EOF && N && M){
input();
solve();
}
end();
}
C - Zhuge Liang’s Password
题意
给出俩矩阵,对第一个矩阵进行旋转,每次旋转90°,问两个矩阵最多会有几个元素相同。
思路
简单模拟就行,找出旋转90°的后矩阵间的规律,然后n^2
找有多少分相同的元素。给Dlz敲去了。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int a[33][33],b[33][33],c[33][33],n;
void xz(int a[33][33],int c[33][33],int x)
{
if(x==0)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
c[i][j]=a[i][j];
}
}
}
else
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
c[i][j]=a[j][n-1-i];
//printf("%d ",c[i][j]);
}
//printf("\n");
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
a[i][j]=c[i][j];
}
}
}
}
int main()
{
while(scanf("%d",&n)!=EOF&&n!=0)
{
int k=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%d",&b[i][j]);
}
}
for(int h=0;h<4;h++)
{
xz(a,c,h);
int z=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(c[i][j]==b[i][j])
z++;
}
}
k=max(z,k);
}
printf("%d\n",k);
}
return 0;
}
H - Rabbit Kingdom
题意
给出一段序列a[1] ~ a[n]
,每次给出查询(l r)
,问区间[l, r]
之中有多少个数与剩下的互质。
(1 <= n, m, W i <= 200000, 1 <= L <= R <= n)
思路
学霸和zq学弟的思路,然而我写了俩礼拜才写出来。先预处理出所有数a[i]
的一个区间的左右端点l[i] r[i]
。在这个区间里的所有数都与a[i]
互质。然后对查询的区间离线,进行区间覆盖。
思路还算简单,但我却写出一堆错误来。总结出几点,预处理时的素因数时候要先筛出sqrt(n)
中的素数, 素因数分解的时候加优化if (_prime[i] * _prime[i] > _s) break;
。线段树可写,但网上的题解都是树状数组的。
code
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 200000 + 5;
int n, m;
int a[MAXN];
struct Ques {
int l, r;
int ans;
int idx;
}q[MAXN];
bool cmp1 (Ques a, Ques b) {
if (a.l == b.l) return a.r < b.r;
return a.l < b.l;
}
bool cmp2 (Ques a, Ques b) {
return a.idx < b.idx;
}
struct Node {
int l, r;
}p[MAXN], t[2*MAXN];
bool cmp (Node a, Node b) {
if (a.l == b.l) return a.r < b.r;
return a.l < b.l;
}
/********************************/
struct Sgtree {
int sg[(1<<19)+10];
void clear() {
memset(sg, 0, sizeof(sg));
}
void push_up (int lr) {
sg[lr] = sg[lr<<1] + sg[lr<<1|1];
}
void update (int l, int r, int lr, int p, int d) {
if (l == r) {
sg[lr] += d;
return ;
}
int m = (l + r) >> 1;
if (p <= m) update(l, m, lr<<1, p, d);
if (p > m) update(m+1, r, lr<<1|1, p, d);
push_up(lr);
}
int query (int l, int r, int lr, int L, int R) {
if (L <= l && r <= R) {
return sg[lr];
}
int m = (l + r) >> 1, res = 0;
if (L <= m) res += query(l, m, lr<<1, L, R);
if (R > m) res += query(m+1, r, lr<<1|1, L, R);
return res;
}
};
/********************************/
Sgtree sg0, sg1;
int _cnt_prime, _prime[500];
inline void init () {
bool vis[500];
memset(vis, true, sizeof(vis));
for (int i=2; i*i<=500; i++) {
if (vis[i] == false) continue;
for (int j=i*i; j<=500; j+=i) {
vis[j] = false;
}
}
_cnt_prime = 0;
for (int i=2; i<=500; i++) {
if (vis[i] == true) {
_prime[_cnt_prime++] = i;
}
}
}
int _cnt_fac, _fac[15];
int _div(int _s) {
_cnt_fac = 0;
for (int i=0; i<_cnt_prime; i++) {
if (_prime[i] * _prime[i] > _s) break;
if (_s % _prime[i] != 0) continue;
for (; _s % _prime[i] == 0; _s /= _prime[i]) {}
_fac[_cnt_fac++] = _prime[i];
}
if (_s != 1) {
_fac[_cnt_fac++] = _s;
}
}
int _visP[MAXN];
inline int _getMAX (int idx) {
_div(a[idx]);
int res = 0;
for (int i=0; i<_cnt_fac; i++) {
res = max(res, _visP[_fac[i]]);
}
return res + 1;
}
inline int _getMIN (int idx) {
_div(a[idx]);
int res = n+1;
for (int i=0; i<_cnt_fac; i++) {
res = min(res, _visP[_fac[i]]);
}
return res - 1;
}
inline void _set (int idx) {
for (int i=0; i<_cnt_fac; i++) {
_visP[_fac[i]] = idx;
}
}
inline void _solve () {
int k=1;
fill(_visP, _visP + MAXN, 0);
for (int i=1; i<=n; i++) {
p[i].l = _getMAX(i);
if (p[i].l != i){
t[k].l = p[i].l;
t[k].r = i-1;
k++;
}
_set(i);
}
fill(_visP, _visP + MAXN, n+1);
for (int i=n; i>=1; i--) {
p[i].r = _getMIN(i);
if (p[i].r != i) {
t[k].l = i+1;
t[k].r = p[i].r;
k++;
}
_set(i);
}
sort(p+1, p+n+1, cmp);
sort(t+1, t+k, cmp);
sg0.clear();
sg1.clear();
for (int i=0, j=1, v=1; i<m; i++) {
while (j <= n && p[j].l <= q[i].l) {
sg0.update(1, n, 1, p[j].r, 1);
j++;
}
while (v < k && t[v].l <= q[i].l) {
sg1.update(1, n, 1, t[v].r, 1);
v++;
}
int cc = sg0.query(1, n, 1, q[i].r, n);
int dd = sg1.query(1, n, 1, q[i].r, n);
q[i].ans = cc - dd;
}
}
int main () {
init();
for (; scanf ("%d %d", &n, &m) == 2; ) {
if (n == 0 && m == 0) break;
for (int i=1; i<=n; i++) {
scanf ("%d", &a[i]);
}
for (int i=0; i<m; i++) {
scanf ("%d %d", &q[i].l, &q[i].r);
q[i].idx = i;
}
sort (q, q+m, cmp1);
_solve();
sort(q, q+m, cmp2);
for (int i=0; i<m; i++) {
printf ("%d\n", q[i].ans);
}
}
return 0;
}