2011 Asia Fuzhou Regional Contest

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;
}


hdu4123 Bob’s Race

树到某一点的最长路可以直接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;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值