11年的福州题目质量都好高,选了5道最简单的来做……
hdu4121 Xiangqi
直接枚举将下一步怎么走,然后看会不会被将死。把帅当只能垂直行动的车看。
有一个点没考虑到,就是将走这一步正好能吃掉红色一个子,后来发现判断是否将死的时候已经处理了这种情况。
代码比较长,一气呵成1Y
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
//#pragma comment(linker, "/STACK:16777216")
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define N 15
int n , X , Y;
int r[N] , c[N];
char t[N];
char g[N][N];
int dx[] = {0 , 1 , 0 , -1} , dy[] = {1 , 0 , -1 , 0};
int dx8[] = {1 , 1 , -1 , -1 , 2 , 2 , -2 , -2} , dy8[] = {2 , -2 , 2 , -2 , 1 , -1 , 1 , -1};
int px[] = {0 , 0 , 0 , 0 , 1 , 1 , -1 , -1} , py[] = {1 , -1 , 1 , -1 , 0 , 0 , 0 , 0};
void work()
{
int i , j , k , x , y; char str[5];
memset(g , 0 , sizeof(g));
for (i = 1 ; i <= n ; ++ i)
{
scanf("%s%d%d",str,&r[i],&c[i]);
g[r[i]][c[i]] = *str;
t[i] = *str;
}
for (j = 0 ; j < 4 ; ++ j)
{
x = X + dx[j] , y = Y + dy[j];
if (x > 3 || x < 1 || y > 6 || y < 4) continue;
for (k = 1 ; k <= n ; ++ k)
{
if (t[k] == 'G')
{
if (y == c[k])
{
for (i = 1 ; i <= n ; ++ i)
if (c[i] == y && r[i] > x && r[i] < r[k])
break;
if (i > n) break;
}
}
if (t[k] == 'R')
{
if (r[k] == x)
{
if (c[k] < y)
{
for (i = c[k] + 1 ; i < y ; ++ i)
if (g[x][i])
break;
if (i >= y) break;
}
if (c[k] > y)
{
for (i = y + 1 ; i < c[k] ; ++ i)
if (g[x][i])
break;
if (i >= c[k]) break;
}
}
if (c[k] == y)
{
if (r[k] < x)
{
for (i = r[k] + 1 ; i < x ; ++ i)
if (g[i][y])
break;
if (i >= x) break;
}
if (r[k] > x)
{
for (i = x + 1 ; i < r[k] ; ++ i)
if (g[i][y])
break;
if (i >= r[k]) break;
}
}
}
if (t[k] == 'C')
{
int sum = 0;
if (r[k] == x)
{
if (c[k] < y)
{
for (i = c[k] + 1 ; i < y ; ++ i)
if (g[x][i])
++ sum;
}
if (c[k] > y)
{
for (i = y + 1 ; i < c[k] ; ++ i)
if (g[x][i])
++ sum;
}
}
if (c[k] == y)
{
if (r[k] < x)
{
for (i = r[k] + 1 ; i < x ; ++ i)
if (g[i][y])
++ sum;
}
if (r[k] > x)
{
for (i = x + 1 ; i < r[k] ; ++ i)
if (g[i][y])
++ sum;
}
}
if (sum == 1) break;
}
if (t[k] == 'H')
{
for (i = 0 ; i < 8 ; ++ i)
{
int hx = r[k] + dx8[i];
int hy = c[k] + dy8[i];
if (hx > 0 && hx <= 9 && hy > 0 && hy <= 10)
{
if (!g[r[k] + px[i]][c[k] + py[i]] && hx == x && hy == y)
break;
}
}
if (i < 8) break;
}
}
if (k > n) break;
}
puts(j >= 4 ? "YES" : "NO");
}
int main()
{
//freopen("~input.txt" , "r" , stdin);
//freopen("output.txt" , "w" , stdout);
while (scanf("%d%d%d",&n,&X,&Y) , n || X || Y)
//int _; scanf("%d",&_); while (_--)
work();
return 0;
}
hdu4122 Alice's mooncake shop
首先各个订单之间不会互相影响,对于一个订单肯定是就在一天把所有月饼做完。
问题就转化为一个RMQ了,把原序列c1,c2....cn转化为c1+(n-1)S,c2+(n-2)S......cn来询问
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
//#pragma comment(linker, "/STACK:16777216")
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define N 2505
int n , m , S , T , c[100005];
char month[][10] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov" , "Dec"};
int day[] = {31,28,31,30,31,30,31,31,30,31,30,31};
int t[N] , num[N];
int check()
{
int y , d , m , h , sum = 0; char str[10];
scanf("%s%d%d%d",str , &d , &y , &h);
int x = y;
while (x > 2000)
{
-- x;
if (x % 100 == 0)
sum += 365 + (x % 400 == 0);
else
sum += 365 + (x % 4 == 0);
}
for (x = 0 ; x < 12 ; ++ x)
if (strcmp(month[x] , str) == 0)
break;
for (int i = 0 ; i < x ; ++ i)
sum += day[i];
sum += d - 1;
if (x >= 2)
{
if (y % 100 == 0)
sum += (y % 400 == 0);
else
sum += (y % 4 == 0);
}
sum *= 24;
return sum + h + 1;
}
int f[17][100005];
void work()
{
int i , j , x ,y , z;
for (i = 1 ; i <= n ; ++ i)
t[i] = check() , scanf("%d",&num[i]);
scanf("%d%d",&T,&S);
memset(f , 0 , sizeof(f));
for (i = 1; i <= m ; ++ i)
scanf("%d",&c[i]) , c[i] += S * (m - i + 1) , f[0][i] = c[i];
for (i = 1 ; 1 << i <= m ; ++ i)
for (j = 1 ; j + (1 << i) - 1 <= m ; ++ j)
f[i][j] = min(f[i - 1][j] , f[i - 1][j + (1 << i - 1)]);
LL ans = 0;
for (i = 1 ; i <= n ; ++ i)
{
y = t[i] , x = max(t[i] - T , 1);
j = log2(y - x + 1);
z = min(f[j][x] , f[j][y - (1 << j) + 1]) - S * (m - y + 1);
ans += (LL) z * num[i];
}
printf("%I64d\n" , ans);
}
int main()
{
while (scanf("%d%d",&n,&m) , n || m)
work();
return 0;
}
树到某一点的最长路可以直接DP出来
剩下的就是找最长的满足要求的区间,先用ST把每个区间的极值处理出来。
然后利用Two-Pointers来不断查找满足要求的区间即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
//#pragma comment(linker, "/STACK:16777216")
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define N 50005
int n , m , pre[N] , mcnt;
struct edge
{
int x , w , next;
}e[N << 1];
pair<int , int> f1[N] , f2[N];
int d[N] , power[18];
void dfs1(int x , int fa)
{
f1[x] = make_pair(0 , x) , f2[x] = make_pair(-1 << 30 , -1);
for (int i = pre[x]; ~i ; i = e[i].next)
{
int y = e[i].x; if (y == fa) continue;
dfs1(y , x);
pair<int , int> tmp(f1[y].fi + e[i].w , y);
if (tmp > f1[x])
f2[x] = f1[x] , f1[x] = tmp;
else if (tmp > f2[x])
f2[x] = tmp;
}
}
void dfs2(int x , int fa)
{
for (int i = pre[x]; ~i ; i = e[i].next)
{
int y = e[i].x; if (y == fa) continue;
if (y != f1[x].se)
d[y] = max(f1[x].fi , d[x]) + e[i].w;
else
d[y] = max(f2[x].fi , d[x]) + e[i].w;
dfs2(y , x);
}
}
int fm[16][N] , fn[16][N];
int Query(int x , int y)
{
int i = upper_bound(power , power + 17 , y - x + 1) - power - 1;
return max(fm[i][x] , fm[i][y - (1 << i) + 1]) - min(fn[i][x] , fn[i][y - (1 << i) + 1]);
}
void work()
{
int i , j , x , y , z;
memset(pre , -1 , sizeof(pre));
mcnt = 0;
for (i = 2 ; i <= n ; ++ i)
{
scanf("%d%d%d",&x,&y,&z);
e[mcnt] = (edge){y , z , pre[x]} , pre[x] = mcnt ++;
e[mcnt] = (edge){x , z , pre[y]} , pre[y] = mcnt ++;
}
dfs1(1 , 0);
dfs2(1 , 0);
for (i = 1 ; i <= n ; ++ i)
fm[0][i] = fn[0][i] = max(f1[i].fi , d[i]);
for (i = 1 ; 1 << i <= n ; ++ i)
for (j = 1 ; j + (1 << i) - 1 <= n ; ++ j)
fm[i][j] = max(fm[i - 1][j] , fm[i - 1][j + (1 << i - 1)]);
for (i = 1 ; 1 << i <= n ; ++ i)
for (j = 1 ; j + (1 << i) - 1 <= n ; ++ j)
fn[i][j] = min(fn[i - 1][j] , fn[i - 1][j + (1 << i - 1)]);
while (m --)
{
scanf("%d",&z) ;int ans = 0;
for (i = 1 , j = 1 ; i <= n ; ++ i)
{
while (Query(j , i) > z)
++ j;
ans = max(i - j + 1 , ans);
}
printf("%d\n",ans);
}
}
int main()
{
power[0] = 1;
for (int i = 1 ; i <= 16 ; ++ i)
power[i] = power[i - 1] << 1;
while (scanf("%d%d",&n,&m) , n || m)
//int _; scanf("%d",&_); while (_--)
work();
return 0;
}
hdu4125 Moles
如果把节点的插入顺序当做另一个关键字的话,这个关键字就满足堆的性质,然后节点元素的关系就是中序遍历产生的。
产生的就是一棵笛卡尔树了,把笛卡尔树用单调栈O(n)构造出来后,用KMP统计。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#pragma comment(linker, "/STACK:16777216")
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define N 600005
int n , a[N] , L[N] , R[N] , m , ca;
char str[7005] , T[N << 1];
int s[N] , top , fail[7005];
void get(int x)
{
T[m ++] = '0' + (x & 1);
if (L[x]) get(L[x]) , T[m ++] = '0' + (x & 1);
if (R[x]) get(R[x]) , T[m ++] = '0' + (x & 1);
}
void work()
{
int i , j , x , len;
scanf("%d",&n);
for (i = 1 ; i <= n ; ++ i)
scanf("%d",&x) , a[x] = i;
scanf("%s" , str);
memset(L , 0 , sizeof(L));
memset(R , 0 , sizeof(R));
for (i = 1 ; i <= n ; ++ i)
{
x = 0;
while (top && a[i] < a[s[top]])
R[s[top - 1]] = s[top] , x = s[top] , s[top --] = 0;
L[i] = x , R[s[top]] = 0;
s[++ top] = i;
}
while (top)
R[s[top - 1]] = s[top] , s[top --] = 0;
fail[0] = fail[1] = 0;
len = strlen(str);
for (i = 1 ; str[i] ;i ++)
{
int j = fail[i];
while (j && str[i] != str[j]) j = fail[j];
fail[i + 1] = str[i] == str[j] ? j + 1 : 0;
}
m = 0 , get(R[0]) , T[m] = 0;
int ans = 0;
for (i = 0 , j = 0 ; T[i] ; i ++) {
while (j && T[i] != str[j]) j = fail[j];
if (T[i] == str[j]) ++ j;
if (j == len) ++ ans;
}
printf("Case #%d: %d\n" ,++ ca , ans);
}
int main()
{
int _; scanf("%d",&_); while (_--)
work();
return 0;
}
hdu4126 Genghis Khan the Conqueror
高虐题
用Prim求出MST之后,在MST上DP出"删去某条边后两棵子树之间的最小距离",就是以每个点为根dfs上一遍。
对于询问,如果增加的是非树边,那MST不变,增加的树边,就用增加后的值以及DP出的值来更新。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
//#pragma comment(linker, "/STACK:16777216")
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define N 3005
int n , m , g[N][N] , dep[N] , cost[N];
int c[N][N] , dp[N][N];
pair<int , int> d[N];
bool f[N];
vector<int> e[N];
int dfs(int pos, int x, int fa) //求pos 点 到 以u为根的树及其子树的最小距离
{
int i , y , ans = 1 << 30;
for(i = 0 ; i < e[x].size() ; i ++) if ((y = e[x][i]) != fa)
{
int tmp = dfs(pos , y , x);
ans = min(ans , tmp);
dp[x][y] = dp[y][x] = min(dp[x][y], tmp); //通过dfs的返回值来更新dp[i][j],怎么更新自己理解吧,我也说不清楚
}
if(pos != fa) //保证这条边不是生成树的边, 不然不能更新
ans = min(ans, g[pos][x]);
return ans;
}
void work()
{
int i , j , x , y , z , ans = 0;
memset(c , 0 , sizeof(c));
for (i = 0 ; i < n ; ++ i)
for (j = 0 ;j < n ; ++ j)
g[i][j] = dp[i][j] = 1 << 30;
for (i = 1 ; i <= m ; ++ i)
{
scanf("%d%d%d",&x,&y,&z);
g[x][y] = g[y][x] = z;
}
for (i = 0 ; i < n ; ++ i)
d[i] = make_pair(g[0][i] , 0) , f[i] = 0 , e[i].clear();
f[0] = 1;
for (i = 1 ; i < n ; ++ i)
{
x = -1;
for (j = 0 ; j < n ; ++ j)
if (!f[j] && (!~x || d[j] < d[x]))
x = j;
ans += d[x].first , f[x] = 1 ;
e[x].pb(d[x].second) , e[d[x].second].pb(x);
c[d[x].second][x] = c[x][d[x].second] = d[x].first;
g[d[x].second][x] = g[x][d[x].second] = 1 << 30;
for (j = 0 ; j < n ; ++ j)
if (!f[j])
d[j] = min(d[j] , make_pair(g[x][j] , x));
}
memset(f , 0 , sizeof(f));
for (i = 0 ; i < n ; ++ i)
dfs(i , i , -1);
int Q; LL sum = 0;
scanf("%d",&Q);
for (i = 1 ; i <= Q ; ++ i)
{
scanf("%d%d%d",&x,&y,&z);
if (c[x][y])
sum += ans - c[x][y] + min(dp[x][y] , z);
else sum += ans;
}
printf("%.4f\n" , 1. * sum / Q);
}
int main()
{
while (scanf("%d%d",&n,&m) , n || m)
//int _; scanf("%d",&_); while (_--)
work();
return 0;
}