2013多校联合训练第四场

A

求一个字符串的回文子序列个数

很直观的DP但一开始看着这个题目愣了好久……

  scanf("%s" , s + 1);
  n = strlen(s + 1);
  memset(f , 0 , sizeof(f));
  for (i = 1 ; i <= n ; ++ i) f[i][i] = 1;
  for (k = 2 ; k <= n ; ++ k)
  {
    for (i = 1 ; i + k - 1 <= n ; ++ i)
    {
      j = i + k - 1;
      f[i][j] = f[i + 1][j] + f[i][j - 1];
      if (s[i] == s[j])
        f[i][j] ++;
      else f[i][j] += (Q - f[i + 1][j - 1]);
      f[i][j] %= Q;
    }
  }
  printf("Case %d: %d\n" , ++ ca , f[1][n]);

C

先预处理出从某个点出发往四个方向滑的终点位置以及路过能拿到的钥匙

然后就是一个BFS了,边权只有1或0,开deque。

可惜因为没有发现卡墙的问题比赛时没有过这个题TwT

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
#define N 205
#define ULL unsigned long long
int n , m , sx , sy , ex , ey;
char s[N][N];
int dx[] = {1 , -1 , 0 , 0} , dy[] = {0 , 0 , 1 , -1};

pair<int , int>  h[4][N][N] , null = make_pair(-1 , -1);
int kn[N][N], key[4][N][N] , ks , ans;

struct opt
{
  int x , y , p , w , r;
};
deque<opt> q;
int d[N][N][128];
bool f[N][N][128];

void update(int x , int y , int p , int v , int w , int r)
{
  if (!f[x][y][p])
  {
    if (w)
      q.push_back((opt){x , y , p , v + w , r});
    else q.push_front((opt){x , y , p , v + w , r});
  }
}
void BFS()
{
  int i , x , y , w , kk = (1 << ks) - 1;
  ans = 1 << 30;
  q.push_back((opt){sx , sy , 0 , 0 , 0});
  memset(f , 0 , sizeof(f));
  while (!q.empty())
  {
    opt a = q.front(); q.pop_front();
    if (f[a.x][a.y][a.p]) continue;
    f[a.x][a.y][a.p] = 1 , w = d[a.x][a.y][a.p] = a.w;
    x = a.x , y = a.y;
    cout << x <<' ' << y << ' ' << a.p << ' ' << w << endl;
    if (x == ex && y == ey)
    {
      if (a.p == kk)
        ans = min(ans , w);
      i = a.r;
      if (s[x + dx[i]][y + dy[i]] == '#' || h[i][x + dx[i]][y + dy[i]] == null) continue;
      update(h[i][x + dx[i]][y + dy[i]].fi , h[i][x + dx[i]][y + dy[i]] .se , a.p | key[i][x + dx[i]][y + dy[i]] , w , 0 , i);
      continue;
    }
    if (s[x][y] < 4)
    {
      i = s[x][y];
      if (s[x + dx[i]][y + dy[i]] == '#' || h[i][x + dx[i]][y + dy[i]] == null) continue;
      update(h[i][x + dx[i]][y + dy[i]].fi , h[i][x + dx[i]][y + dy[i]] .se , a.p | key[i][x + dx[i]][y + dy[i]] , w , 0 , i);
      continue;
    }
    for (i = 0 ; i < 4 ; ++ i)
      if (h[i][x][y] != null)
        update(h[i][x][y].fi , h[i][x][y].se , a.p | key[i][x][y] , w , 1 , i);
  }
  if (ans == 1 << 30)
    ans = -1;
  printf("%d\n" , ans);
}
void work()
{
  int i , j;
  memset(s , 0 , sizeof(s));
  memset(h , 0 , sizeof(h));
  memset(kn , -1 , sizeof(kn));
  memset(key , 0 , sizeof(key));
  ks = 0;

  for (i = 1 ; i <= n ; ++ i)
    scanf("%s" , s[i] + 1);
  for (i = 1 ; i <= n ; ++ i)
    for (j = 1 ; j <= m ; ++ j)
    {
      if (s[i][j] == 'S')
        sx = i , sy = j;
      if (s[i][j] == 'E')
        ex = i , ey = j;
      if (s[i][j] == 'K')
        kn[i][j] = ks ++;
    }
  for (i = 1 ; i <= n ; ++ i)
    for (j = 1 ; j <= m ; ++ j)
    {
      if (s[i][j] == 'U')
        s[i][j] = 1;
      if (s[i][j] == 'D')
        s[i][j] = 0;
      if (s[i][j] == 'L')
        s[i][j] = 3;
      if (s[i][j] == 'R')
        s[i][j] = 2;
    }
  for (i = n + 1; i > 0 ; -- i)
    for (j = 1 ; j <= m ; ++ j)
    {
      if (i == n + 1) h[0][i][j] = null;
      else
      {
        if (s[i][j] < 4 || s[i][j] == 'E') h[0][i][j] = make_pair(i , j) , key[0][i][j] = 0;
        else if (s[i + 1][j] != '#')
        {
          h[0][i][j] = h[0][i + 1][j];
          key[0][i][j] = key[0][i + 1][j];
          key[0][i][j] |= ~kn[i][j] ? (1 << kn[i][j]) : 0;
        }
        else
        {
          h[0][i][j] = make_pair(i , j);
          key[0][i][j] = ~kn[i][j] ? (1 << kn[i][j]) : 0;
        }
      }
    }

  for (i = 0 ; i <= n ; ++ i)
    for (j = 1 ; j <= m ; ++ j)
    {
      if (i == 0) h[1][i][j] = null;
      else
      {
        if (s[i][j] < 4 || s[i][j] == 'E') h[1][i][j] = make_pair(i , j) , key[1][i][j] = 0;
        else if (s[i - 1][j] != '#')
        {
          h[1][i][j] = h[1][i - 1][j];
          key[1][i][j] = key[1][i - 1][j];
          key[1][i][j] |= ~kn[i][j] ? (1 << kn[i][j]) : 0;
        }
        else
        {
          h[1][i][j] = make_pair(i , j);
          key[1][i][j] = ~kn[i][j] ? (1 << kn[i][j]) : 0;
        }
      }
    }
  for (j = m + 1 ; j > 0 ; -- j)
    for (i = 1 ; i <= n ; ++ i)
    {
      if (j == m + 1) h[2][i][j] = null;
      else
      {
        if (s[i][j] < 4 || s[i][j] == 'E') h[2][i][j] = make_pair(i , j) , key[2][i][j] = 0;
        else if (s[i][j + 1] != '#')
        {
          h[2][i][j] = h[2][i][j + 1];
          key[2][i][j] = key[2][i][j + 1];
          key[2][i][j] |= ~kn[i][j] ? (1 << kn[i][j]) : 0;
        }
        else
        {
          h[2][i][j] = make_pair(i , j);
          key[2][i][j] = ~kn[i][j] ? (1 << kn[i][j]) : 0;
        }
      }
    }
  for (j = 0 ; j <= m ; ++ j)
    for (i = 1 ; i <= n ; ++ i)
    {
      if (j == 0) h[3][i][j] = null;
      else
      {
        if (s[i][j] < 4 || s[i][j] == 'E') h[3][i][j] = make_pair(i , j) , key[3][i][j] = 0;
        else if (s[i][j - 1] != '#')
        {
          h[3][i][j] = h[3][i][j - 1];
          key[3][i][j] = key[3][i][j - 1];
          key[3][i][j] |= ~kn[i][j] ? (1 << kn[i][j]) : 0;
        }
        else
        {
          h[3][i][j] = make_pair(i , j);
          key[3][i][j] = ~kn[i][j] ? (1 << kn[i][j]) : 0;
        }
      }
    }
  BFS();
}
int main()
{
  freopen("input.txt","r",stdin);
  while (~scanf("%d%d",&n,&m))
    work();
  return 0;
}

D

SCC缩点之后再枚举割掉的所有入度为0或者出度为0的SCC,更新答案。

代码主要部分不是我写的

#pragma comment(linker,"/STACK:102400000,102400000")

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 100010
#define M 200010

int sum,first[N];
struct gtype {
       int x,y,next;
}g[M];

int cas,n,m,a,b,tot,top,cnt,pin[N],pout[N];
int low[N],dfn[N],con[N],stack[N],belong[N];
bool instack[N];

bool cmp(int a, int b) {
     return a>b;
}

void add(int x,int y) {
     sum++;
     g[sum].x = x;
     g[sum].y = y;
     g[sum].next = first[x];
     first[x] = sum;
}

void tarjan(int x) {
    int k;
    dfn[x] = low[x] = ++tot;
    instack[x] = true;
    stack[++top] = x;
    for (int t=first[x];t!=-1;t=g[t].next) {
        int y = g[t].y;
        if (!dfn[y]) {
            tarjan(y);
            low[x] = min(low[x],low[y]);
        }
        else if (instack[y]) low[x] = min(low[x],dfn[y]);
    }
    if (dfn[x]==low[x]) {
        cnt++;
        do {
            k = stack[top--];
            instack[k] = false;
            belong[k] = cnt;
            con[cnt]++;
        }while (k!=x);
    }
}

int main() {
    scanf("%d",&cas);
    for (int tt=1;tt<=cas;tt++) {
        sum = 0;
        memset(first,-1,sizeof(first));
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++) {
            scanf("%d%d",&a,&b);
            add(a,b);
        }

        tot = top = cnt = 0;
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(con,0,sizeof(con));
        memset(instack,0,sizeof(instack));
        for (int i=1;i<=n;i++)
            if (!dfn[i]) tarjan(i);

        printf("Case %d: ",tt);
        if (cnt==1) {
           printf("-1\n");
        }
        else {
             long long ans = 0;
             memset(pin,0,sizeof(pin));
             memset(pout,0,sizeof(pout));
             for (int i=1;i<=m;i++) {
                 if (belong[g[i].x] != belong[g[i].y]) {
                    pout[belong[g[i].x]]++;
                    pin[belong[g[i].y]]++;
                 }
             }
             for (int i=1;i<=cnt;i++)
             {
                 if (pin[i]==0)
                 {
                    ans = max(ans, (long long)n*(n-1)-m-(long long)(n-con[i])*con[i]);
                 }
                 if (pout[i]==0)
                 {
                    ans = max(ans, (long long)n*(n-1)-m-(long long)(n-con[i])*con[i]);
                 }
             }
             printf("%I64d\n",ans);
        }
    }
    return 0;
}

G

比赛结束了才被DS提醒是被水了过去……

之前用线段树想的太麻烦,后来才发现可以用数组直接模拟分为了多少段

#pragma comment(linker,"/STACK:102400000,102400000")
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#define maxn 100010
using namespace std;
typedef long long LL;
int pos[maxn],color[maxn],n,m;
void RD(int& x)
{
  x = 0; char c;
  for (c = getchar() ;!isdigit(c) ; c = getchar()); x = c - '0';
  for (c = getchar() ; isdigit(c) ; c = getchar()) x = x * 10 + c - '0';
}
struct Question
{
    int l,r,id;
    int a;
    friend bool operator < (const Question &a,const Question &b)
    {
        return pos[a.l]<pos[b.l]||(pos[a.l]==pos[b.l]&&a.r<b.r);
    }
}ask[maxn];
bool cmp_id(const Question &a,const Question &b)
{
    return a.id<b.id;
}
bool ff[maxn];
int anss;
void read()
{
    RD(n) , RD(m);
    memset(ff , 0 , sizeof(ff));
    for(int i=1;i<=n;i++)
        RD(color[i]);
    int limit=(int)sqrt(n+0.5);
    for(int j=1;j<=n;j++)
        pos[j]=(j-1)/limit+1;
    for(int i=1;i<=m;i++)
    {
        RD(ask[i].l) , RD(ask[i].r);
        ask[i].id=i;
    }
    sort(ask+1,ask+m+1);
}

void Modify(int i,int add)
{
  if (add == 1)
  {
        int x = color[i];
        ff[x] = 1;
        if (ff[x - 1] && ff[x + 1]) -- anss;
        else if (!ff[x - 1] && !ff[x + 1]) ++ anss;
  }
  else
  {
        int x = color[i];
        ff[x] = 0;
        if (ff[x - 1] && ff[x + 1]) ++ anss;
        else if (!ff[x - 1] && !ff[x + 1]) -- anss;
  }
}
void work()
{
    anss=0;
    for(int i=1,l=1,r=0;i<=m;i++)
    {
        if(r<ask[i].r)
        {
            for(r=r+1;r<=ask[i].r;r++)
                Modify(r,1);
            r--;
        }
        if(r>ask[i].r)
            for(;r>ask[i].r;r--)
                Modify(r,-1);
        if(l<ask[i].l)
            for(;l<ask[i].l;l++)
                Modify(l,-1);
        else if(l>ask[i].l)
        {
            for(l=l-1;l>=ask[i].l;l--)
                Modify(l,1);
            l++;
        }
        ask[i].a=anss;
    }
}
void print()
{
    sort(ask+1,ask+m+1,cmp_id);
    for(int i=1;i<=m;i++)
        printf("%d\n",ask[i].a);
}
int main()
{
  int _; RD(_); while (_--)
    read(),
    work(),
    print();
  return 0;
}

H

每一组hehehehe明显可以分开处理,一段长度为n的hehe....he的方案就是斐波那契的[n/2+1]项,乘起来就ok

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
#define N 15005
#define M 2000005
typedef long long LL;
using namespace std;
char s[N];
int n , m , a[N] , Q = 10007 , f[N] , ca;
void work()
{
  int i , j , ans = 1 , x;
  scanf("%s", s);
  n = strlen(s);
  m = 0;
  for (i = 0 ; i + 3 < n ; ++ i)
    if (s[i] == 'h' && s[i + 1] == 'e' && s[i + 2] == 'h' && s[i + 3] == 'e')
      a[m ++] = i;
  for (i = 0 ; i < m ; i = j)
  {
    j = i + 1 , x = 1;
    while (a[j] - a[j - 1] == 2)
      ++ j , ++ x;
    ans *= f[x] , ans %= Q;
  }
  printf("Case %d: %d\n" , ++ ca , ans);
}

int main()
{
  f[0] = 1 , f[1] = 2;
  for (int i = 2 ; i <= 10086 ; ++ i)
    f[i] = f[i - 1] + f[i - 2] , f[i] %= Q;
  int _; cin >> _ ; while (_ --)
    work();
  return 0;
}

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值