2012 Asia ChangChun Regional Contest

hdu4421 Bit Magic

2-SAT,也可以根据异或的关系用并查集直接把解求出来,然后判定是否满足与或非的限制。

还是2-SAT写起来爽……

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#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 505
int B[N][N] , n , K;

int pre[N + N] , mcnt;
struct edge
{
  int x , next;
}e[N * N * 16];

void addedge(int x , int y)
{
  e[mcnt].x = y , e[mcnt].next = pre[x] , pre[x] = mcnt ++;
}
void build()
{
  int i , j;
  memset(pre, -1 , sizeof(pre));
  mcnt = 0;
  // + n == 1 , no n == 0
  for (i = 0 ; i < n ; ++ i)
  {
    for (j = i + 1 ; j < n ; ++ j)
    {
      if (i % 2 == 0 && j % 2 == 0)
      {
        if (B[i][j] & (1 << K))
        {
          addedge(i , i + n);
          addedge(j , j + n);
          addedge(i + n , j + n);
          addedge(j + n , i + n);
        }
        else
        {
          addedge(i + n , j);
          addedge(j + n , i);
        }
      }
      else if (i % 2 == 1 && j % 2 == 1)
      {
        if (B[i][j] & (1 << K))
        {
          addedge(i , j + n);
          addedge(j , i + n);
        }
        else
        {
          addedge(i + n , i);
          addedge(j + n , j);
          addedge(i , j);
          addedge(j , i);
        }
      }
      else
      {
        if (B[i][j] & (1 << K))
        {
          addedge(i , j + n);
          addedge(j , i + n);
          addedge(i + n , j);
          addedge(j + n , i);
        }
        else
        {
          addedge(i , j);
          addedge(j , i);
          addedge(i + n , j + n);
          addedge(j + n , i + n);
        }
      }
    }
  }
}
int DFN[N + N] , low[N + N] , bel[N + N] , ncnt , bcnt;
stack<int> S; bool in[N + N];

bool tarjan(int x)
{
  DFN[x] = low[x] = ++ ncnt;
  S.push(x) , in[x] = 1;
  for (int i = pre[x] ; ~i ; i = e[i].next)
  {
    int y = e[i].x;
    if (!DFN[y])
    {
      tarjan(y);
      low[x] = min(low[x] , DFN[y]);
    }
    else if (in[y])
      low[x] = min(low[x] , low[y]);
  }
  if (DFN[x] == low[x])
  {
    ++ bcnt; int y;
    do
    {
      y = S.top() , S.pop();
      in[y] = 0 , bel[y] = bcnt;
    }while (y != x);
  }
}

bool check()
{
  memset(DFN , 0 , sizeof(DFN));
  memset(low , 0 , sizeof(low));
  ncnt = bcnt = 0;
  for (int i = 0 ; i < n + n ; ++ i)
    if (!DFN[i])
      tarjan(i);
  for (int i = 0 ; i < n ; ++ i)
    if (bel[i] == bel[i + n])
      return 0;
  return 1;
}

void work()
{
  int i , j;
  for (i = 0 ; i < n ; ++ i)
    for (j = 0 ; j < n ; ++ j)
      scanf("%d",&B[i][j]);
  for (K = 0 ; K < 31 ; ++ K)
  {
    build();
    if (!check())
      break;
  }
  puts(K < 31 ? "NO" : "YES");
}

int main()
{
  while (~scanf("%d",&n))
    work();
  return 0;
}


hdu4422 The Little Girl who Picks Mushrooms

题意只要理解了就不难了,答案最多只有1024,n<=3时结果肯定为1024,n=5时可以直接枚举,n=4时也可以枚举第5座山摘了多少然后和n=5一样处理

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#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 505
int n , a[N];

void work()
{
  int i , j , k , l , sum = 0 , ans = 0, x;
  for (i = 1 ; i <= n ; ++ i)
    scanf("%d",&a[i]) , sum += a[i];
  if (n <= 3)
  {
    puts("1024");
    return;
  }
  if (n == 4)
  {
    ++ n;
    for (a[n] = 0 ; a[n] <= 2012 ; ++ a[n])
    {
      for (i = 1 ; i <= n ; ++ i)
        for (j = i + 1 ; j <= n ; ++ j)
          for (k = j + 1 ; k <= n ; ++ k)
            if ((a[i] + a[j] + a[k]) % 1024 == 0)
            {
              x = (sum - a[i] - a[j] - a[k] - 1) % 1024 + 1;
              ans = max(x , ans);
            }
      ++ sum;
    }
    printf("%d\n" , ans);
    return;
  }
  if (n == 5)
  {
    for (i = 1 ; i <= n ; ++ i)
      for (j = i + 1 ; j <= n ; ++ j)
        for (k = j + 1 ; k <= n ; ++ k)
          if ((a[i] + a[j] + a[k]) % 1024 == 0)
          {
            x = (sum - a[i] - a[j] - a[k] - 1) % 1024 + 1;
            ans = max(x , ans);
          }
    printf("%d\n" , ans);
  }
}

int main()
{
  while (~scanf("%d",&n))
    work();
  return 0;
}

hdu4424 Conquer a New Region

将边从大到小排序,这样访问每条边的时候就可以保证这条边就是所连接两个集合的瓶颈,就可以判断汇点在哪边的集合较优,用并查集维护。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#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 200005
int n , m , f[N] , s[N];
LL d[N];
pair<int , pair<int , int> > a[N];

int getf(int x) {return x == f[x] ? x : f[x] = getf(f[x]);}

void work()
{
  int i , x , y ;
  LL ans = 0 , sx , sy;
  for (i = 0 ; i < n - 1 ; ++ i)
    scanf("%d%d%d",&a[i].se.fi , &a[i].se.se , &a[i].fi);
  for (i = 1 ; i <= n ; ++ i)
    f[i] = i , s[i] = 1 , d[i] = 0;
  sort(a , a + n - 1 , greater< pair<int , pair<int , int> > >() );

  for (i = 0 ; i + 1 < n ; ++ i)
  {
    x = getf(a[i].se.fi) , y = getf(a[i].se.se);
    sx = d[x] + (LL) s[y] * a[i].fi;
    sy = d[y] + (LL) s[x] * a[i].fi;
    if (sx > sy)
      f[y] = x , s[x] += s[y] , d[x] = sx;
    else
      f[x] = y , s[y] += s[x] , d[y] = sy;
  }
  for (i = 1 ; i <= n ; ++ i)
    if (getf(i) == i)
      break;
  cout << d[i] << endl;
}

int main()
{
  while (~scanf("%d",&n))
    work();
  return 0;
}

hdu4426 Palindromic Substring

manacher预处理之后就能利用hash统计出整个字符串有多少种回文串,同时统计字符串出现的次数,方法参考的

http://www.mzry1992.com/blog/miao/2012changchun-regional-g.html

统计出来以后对于每次询问只需要暴力计算排序即可

WA了N次的原因是K没有开longlong

#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 200005
char str[N >> 1] , s[N];
int p[N] , n , m , val[27] , ca;
ULL hash[N >> 1] , MAGIC = 67 , power[N >> 1];
LL K;
int Q = 777777777 , p2[N >> 1] , ra[N >> 1];
struct contain
{
  ULL h ;
  int l , t , pre;
  bool operator < (const contain& r) const{
    return l > r.l;}
}pl[N];
map< pair<ULL , int> , int> id;
ULL get(int x , int y)
{
  return hash[y] - hash[x - 1] * power[y - x + 1];
}
int get2(int x , int y)
{
  return (Q + ra[y] - (LL)ra[x - 1] * p2[y - x + 1] % Q) % Q;
}
pair<int , int> od[N];
void work()
{
  int i , j , k , len = 1 , ans = 0;
  scanf("%d%d%s" , &n , &m , str);
  s[0] = '%';
  for (i = 0 ; str[i] ; ++ i)
    s[len ++] = '#' , s[len ++] = str[i]; s[len ++] = '#';s[len] = 0;
  for (i = 1 ; i <= n ; ++ i)
    hash[i] = hash[i - 1] * MAGIC + (str[i - 1] - 'a' + 1);
  int iid = 0 , mx = 0;
  for (i = 0 ; i != len ; ++ i)
  {
    p[i] = mx > i ? min(p[iid + iid - i], mx - i) : 1;
    while (s[i + p[i]] == s[i - p[i]]) ++ p[i];
    if (i + p[i] > mx)
      mx = i + p[i] , iid = i;
  }

    int sum = 0;
    ULL x , y;
    id.clear();
    for (i = 2 ; i + 1 != len ; ++ i)
    {
      j = p[i] - (s[i] == '#');
      while (j > 1)
      {
        x = get((i - j >> 1) + 1 , i >> 1);
        if (!(k = id[make_pair(x , j >> 1)]))
        {
          id[make_pair(x , j >> 1)] = ++ sum;
          pl[sum] = (contain) {x , j >> 1 , 1 , i >> 1};
        }
        else
        {
          ++ pl[k].t;
          break;
        }
        j -= 2;
      }
    }
    //for (i = 1 ; i <= sum ; ++ i)
   //   printf("%d\n" , pl[i].h2 , " \n"[i == sum]);
    sort(pl + 1 , pl + sum + 1);
    id.clear();
    for (i = 1 ; i <= sum ; ++ i)
      id[make_pair(pl[i].h , pl[i].l)] = i;
    for (i = 1 ; i <= sum ; ++ i)
    {
      x = pl[i].h , j = pl[i].l;
      if (j > 1)
      {
        x -= power[j - 1] * (str[pl[i].pre - j] - 'a' + 1) , -- j;
        if (id.count(make_pair(x , j)))
          pl[id[make_pair(x , j)]].t += pl[i].t - 1;
      }
    }

  while (m --)
  {
    scanf("%I64d" , &K);
    for (i = 0 ; i < 26 ; ++ i)
      scanf("%d" , &val[i]);
    for (i = 1 ; i <= n ; ++ i)
      ra[i] = ((LL)ra[i - 1] * 26 % Q + (val[str[i - 1] - 'a'])) % Q ;
    for (i = 1 ; i <= sum ; ++ i)
      od[i] = make_pair(get2( pl[i].pre - pl[i].l + 1 , pl[i].pre) , pl[i].t);
    sort(od + 1 , od + sum + 1);
    for (i = 1 ; i <= sum ; ++ i)
    {
      K -= od[i].se;
      if (K <= 0)
      {
        printf("%d\n" , od[i].fi);
        break;
      }
    }
  }
  puts("");
}

int main()
{
  std::ios::sync_with_stdio(false);
  power[0] = p2[0] = 1;
  for (int i = 1 ; i <= 100000 ; ++ i)
    power[i] = power[i - 1] * MAGIC , p2[i] = (LL) p2[i - 1] * 26 % Q;
  int _; scanf("%d",&_); while (_--)
    work();
  return 0;
}

hdu4427 Math Magic

DP,集合中的每个数字都肯定M的约数,需要预处理出这些约数的LCM,不然会T……

#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 1005
int n , m , K , Q = 1e9 + 7;
int f[2][1001][100] , lcm[100][100];
int bel[N] , fal[N] , sum;
void work()
{
  int i , j , k , l , x;
  sum = 0 , memset(bel , 0 , sizeof(bel));
  for (i = 1 ; i * i <= m ; ++ i)
    if (m % i == 0)
    {
      fal[++ sum] = i;
      if (m != i * i)
        fal[++ sum] = m / i;
    }
  sort(fal + 1 , fal + 1 + sum);
  for (i = 1 ; i <= sum ; ++ i)
    bel[fal[i]] = i;
  for (i = 1 ; i <= sum ; ++ i)
    for (j = 1 ; j <= sum ; ++ j)
      lcm[i][j] = fal[i] / __gcd(fal[i] , fal[j]) * fal[j];

  memset(f , 0 , sizeof(f));
  f[0][0][1] = 1;
  for (k = 0 ; k < K ; ++ k)
  {
    memset(f[!(k & 1)] , 0 , sizeof(f[k & 1]));
    for (i = 0 ; i <= n ; ++ i)
      for (j = 1 ; j <= sum ; ++ j) if (f[k & 1][i][j])
      {
        for (l = 1 ; i + fal[l] <= n &&  l <= sum ; ++ l)
        {
          x = lcm[j][l];
          f[!(k & 1)][i + fal[l]][bel[x]] += f[k & 1][i][j];
          if (f[!(k & 1)][i + fal[l]][bel[x]] >= Q)
            f[!(k & 1)][i + fal[l]][bel[x]] -= Q;
        }
      }
  }
  printf("%d\n" , f[K & 1][n][bel[m]]);
}

int main()
{
  std::ios::sync_with_stdio(false);
  while (cin >> n >> m >> K)
    work();
  return 0;
}

hdu4429 Split the Rectangle

根据矩形的分割顺序可以构建出一棵二叉树,然后要让两个矩形内的点在一个空矩形里面就意味着两个矩形的LCA代表的矩形要整个变空。

询问就转化成了询问两个叶子的LCA,返回LCA的子树的叶子数。

#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 2005

int n , Q , f[N] , d[N] , m , sum[N];
int xl , yl , xr , yr;
struct rect
{
  int x1 , x2 , y1 , y2 , id;
}rec[N];
void work()
{
  int i , j , x , y , ans;
  rec[m = 1] = (rect) {xl , xr , yl , yr , 1};
  cin >> n >> Q;
  memset(f , 0 , sizeof(f));
  memset(sum , 0 , sizeof(sum));
  for (j = 1 ; j <= n ; ++ j)
  {
    cin >> xl >> yl >> xr >> yr;
    if (xl > xr) swap(xl , xr);
    if (yl > yr) swap(yl , yr);
    for (i = 1 ; i <= m ; ++ i)
      if (rec[i].id)
      {
        if (xl == xr)
        {
          if (yl == rec[i].y1 && yr == rec[i].y2 && xl >= rec[i].x1 && xr <= rec[i].x2)
          {
            f[++ m] = rec[i].id , d[m] = d[rec[i].id] + 1 , rec[m] = (rect) {rec[i].x1 , xl , rec[i].y1 , rec[i].y2 , m};
            f[++ m] = rec[i].id , d[m] = d[rec[i].id] + 1 , rec[m] = (rect) {xl , rec[i].x2 , rec[i].y1 , rec[i].y2 , m};
            rec[i].id = 0;
            break;
          }
        }
        if (yl == yr)
        {
          if (xl == rec[i].x1 && xr == rec[i].x2 && yl >= rec[i].y1 && yr <= rec[i].y2)
          {
            f[++ m] = rec[i].id , d[m] = d[rec[i].id] + 1 , rec[m] = (rect) {rec[i].x1 , rec[i].x2 , rec[i].y1 , yl , m};
            f[++ m] = rec[i].id , d[m] = d[rec[i].id] + 1 , rec[m] = (rect) {rec[i].x1 , rec[i].x2 , yr , rec[i].y2 , m};
            rec[i].id = 0;
            break;
          }
        }
      }
  }
  for (i = 1 ; i <= m ; ++ i)
    if (rec[i].id)
    {
      x = i;
      while (x)
        ++ sum[x] , x = f[x];
    }

  while (Q --)
  {
    cin >> xl >> yl >> xr >> yr;
    for (i = 1 ; i <= m ; ++ i)
      if (rec[i].id)
      {
        if (xl >= rec[i].x1 && xl <= rec[i].x2 && yl >= rec[i].y1 && yl <= rec[i].y2)
          break;
      }
    x = i;
    for (i = 1 ; i <= m ; ++ i)
      if (rec[i].id)
      {
        if (xr >= rec[i].x1 && xr <= rec[i].x2 && yr >= rec[i].y1 && yr <= rec[i].y2)
          break;
      }
    y = i;
    if (d[x] > d[y]) swap(x , y);
    while (d[x] != d[y])
      y = f[y] , ++ ans;
    while (x != y)
      y = f[y] , x = f[x] , ans += 2;
    //cout << ans << endl;
    cout << n + 2 - sum[x] << endl;
  }

}

int main()
{
  std::ios::sync_with_stdio(false);
  while (cin >> xl >> yl >> xr >> yr)
    work();
  return 0;
}


hdu4430 Yukari's Birthday

因为K>=2所以R不怎么大,就可以枚举所有R,K的一个上界就是pow(n , 1/r),二分查找满足要求的K即可。
#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 200005

LL n;
pair<LL , LL> ans;

LL cal(int k , int r)
{
  LL x = 1 , sum = 0;
  for (int i = 1 ; i <= r ; ++ i)
    x *= k , sum += x;
  return sum;
}

void work()
{
  LL sum , x , y;
  int r , k , top , bot , m;
  ans = make_pair(n - 1 , 1);
  for (r = 2 ; r <= 39 ; ++ r)
  {
    top = 2 , bot = pow(n , 1.0 / r) + 2;
    while (top <= bot)
    {
      m = (top + bot) >> 1 , sum = cal(m , r);
      if (sum == n)
      {
        ans = min(ans , make_pair((LL)r * m , (LL)r));
        break;
      }
      if (sum > n) bot = m - 1; else top = m + 1;
    }
  }
  -- n;
  for (r = 2 ; r <= 39 ; ++ r)
  {
    top = 2 , bot = pow(n , 1.0 / r) + 2;
    while (top <= bot)
    {
      m = (top + bot) >> 1 , sum = cal(m , r);
      if (sum == n)
      {
        ans = min(ans , make_pair((LL)r * m , (LL)r));
        break;
      }
      if (sum > n) bot = m - 1; else top = m + 1;
    }
  }

  printf("%I64d %I64d\n" , ans.se , ans.fi / ans.se);
}

int main()
{
  std::ios::sync_with_stdio(false);
  while (cin >> n)
    work();
  return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值