HZNU Training 4 for Zhejiang Provincial Collegiate Programming Contest 2019

今日這場比賽咱們準備的題比較全面,二分+數論+最短路+計算幾何+dp+思惟+簽到題等。有較難的防AK題,也有簡單的簽到題。爲你們準備了一份題解和AC代碼。node

A - Meeting with Aliens

 UVA - 10570 ios

題目意思:讓一個成環的序列變成有序的,正序逆序均可以,問最小交換次數。算法

解題思路:對於一個長度爲n的元素互異的序列,經過交換實現有序的最小的交換次數是=n - 被分解成單循環的個數。數據比較小,正着來一遍,反着來一遍,取最小就能夠了。數組

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<string>
#include<vector>
#include<ctime>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define ll long long
#define MAXN 101000
#define mod ((int)1e9+7)

const int maxn = 500 + 10;

int n;
int num[maxn << 1];
bool vis[maxn];

void dfs(int st, int a) {
    if (vis[a]) return;
    vis[a] = true;
    dfs(st, num[st + a - 1]);
}

void dfs2(int st, int a) {
    if (vis[a]) return;
    vis[a] = true;
    dfs2(st, num[st - a + 1]);
}

int main()
{
    //freopen("input.txt", "r", stdin);
    while (~scanf("%d", &n) && n) {
        for (int i = 0; i < n; i++) {
            scanf("%d", &num[i]);
            num[i + n] = num[i];
        }

        int Max = 0;

        for (int st = 0; st < n; st++) {
            memset(vis, false, sizeof(vis));
            int cnt = 0;
            for (int i = st; i < st + n; i++) {
                if (!vis[num[i]]) {
                    dfs(st, num[i]);
                    cnt++;
                }
            }
            Max = Max > cnt ? Max : cnt;
        }

        for (int st = 2 * n - 1; st >= n; st--) {
            memset(vis, false, sizeof(vis));
            int cnt = 0;
            for (int i = st; i >= st - n + 1; i--) {
                if (!vis[num[i]]) {
                    dfs2(st, num[i]);
                    cnt++;
                }
            }
            Max = Max > cnt ? Max : cnt;
        }

        printf("%d\n", n - Max);
    }
    return 0;
}
View Code

B - Bi-shoe and Phi-shoe

 LightOJ - 1370 ide

歐拉函數函數

題意:給定值,求知足歐拉值大於等於這個數的最小的數。this

題解:預處理存下來,從x+1(x是幸運數字)開始找第一個出現的素數,那就是最小花費。spa

/*

 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 I have a dream!A AC deram!!
 orz orz orz orz orz orz orz orz orz orz orz
 orz orz orz orz orz orz orz orz orz orz orz
 orz orz orz orz orz orz orz orz orz orz orz

 */

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<stdlib.h>
using namespace std;
typedef long long LL;
typedef unsigned long long int ull;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int maxn = 2000 + 5;
int euler[1001000];
void Is_prime()
{
    memset(euler,0,sizeof(euler));
    euler[1]=1;
    for(int i=2;i<=1000;i++)
    {
        if(!euler[i])
        {
            for(int j=2*i;j<1000000+100;j+=i)
            {
                euler[j]=1;
            }
        }
    }
}
int main()
{
    int T,t=0;
    scanf("%d",&T);
    Is_prime();
    while(T--)
    {
        int n;
        scanf("%d",&n);
        LL ans=0;
        for(int i=0;i<n;i++)
        {
            int x;
            scanf("%d",&x);
            for(int j=x+1;;j++)
            {
                if(!euler[j])
                {
                    ans+=j;
                    break;
                }
            }
        }
        printf("Case %d: %lld Xukha\n",++t,ans);
    }
}
View Code

 

C - Highways

 POJ - 1751 .net

題意:首行給出N,表明有1~N共N個點。接下來N行,每行兩個數x,y,表明第i個點的座標。接着給出M,接着M行,每行兩個數x,y,表明第x個點和第y個點已經聯通(即x到y的權值爲0),創建最小生成樹,輸出生成樹中權值不爲0的邊的兩端的點的編號。code

題解:最壞的狀況須要遍歷圖中的每一條邊,很明顯的稠密圖,優先選用普利姆算法。根據座標創建無向圖,權值設爲距離的平方便可,這樣能夠避免sqrt後權值變爲double型,避免精度損失。對於已聯通的兩點,更新這兩點的權值爲0便可。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<string>
#include<vector>
#include<ctime>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define ll long long
#define MAXN 101000
#define mod ((int)1e9+7)
const int maxn=751;
const int INF=0x3f3f3f3f;
int map[maxn][maxn];
int dis[maxn];
int vis[maxn];
int Edge[maxn];//i到Edge[i]是一條生成樹內的邊
struct node
{
    int x;
    int y;
} Point[maxn]; //第i個點的座標
int N;//點的數量
int M;//更新邊的數量
void init()
{
    scanf("%d",&N);
    for(int i=1; i<=N; i++)//建圖
    {
        scanf("%d%d",&Point[i].x,&Point[i].y);
        for(int j=1; j<i; j++)//爲何這裏不取sqrt,由於徹底不必
            map[i][j]=map[j][i]=(Point[i].x-Point[j].x)*(Point[i].x-Point[j].x)+(Point[i].y-Point[j].y)*(Point[i].y-Point[j].y);
        map[i][i]=INF;//本身不可能到本身
    }
    scanf("%d",&M);
    int x,y;
    while(M--)//更新圖
    {
        scanf("%d%d",&x,&y);
        map[x][y]=map[y][x]=0;
    }
    memset(vis,0,sizeof(vis));
    vis[1]=1;
    for(int i=1; i<=N; i++)
    {
        dis[i]=map[i][1];
        Edge[i]=1;//初始化爲存儲i到1的邊
    }
}
void Prim()
{
    for(int i=1; i<N; i++)
    {
        int minn=INF;
        int point_minn;
        for(int j=1; j<=N; j++)
            if(vis[j]==0&&minn>dis[j])
            {
                minn=dis[j];
                point_minn=j;
            }
        vis[point_minn]=1;
        for(int k=1; k<=N; k++)
            if(vis[k]==0&&dis[k]>map[point_minn][k])
            {
                Edge[k]=point_minn;//這裏是輸出方式的技巧
                dis[k]=map[point_minn][k];
            }
        if(map[Edge[point_minn]][point_minn])
            printf("%d %d\n",Edge[point_minn],point_minn);
    }
}
int main()
{
    init();
    Prim();
    return 0;
}
View Code

D - Maze

 CodeForces - 377A 

題意:給你一個圖,將k個‘.’變成‘X’,使剩下的‘.’仍然連通,圖中還有‘#’。

題解:思惟關鍵點是既然他要你修改k個,那麼假設一開始有s個,則dfs搜索到k-s個的時候中止就行了,沒被搜索到的就是要修改的,這樣能夠保證剩下的一定連通。

#include <iostream>
#include <cstdio>
#include <cstring>
int n,m,k;
int go[4][2]={0,1,1,0,0,-1,-1,0};
char map[505][505];
int book[505][505];
using namespace std;
void dfs(int r,int c)
{
    if(!k)
    return ;
    k--;
    //map[r][c]='0';
    book[r][c]=1;//將要修改的標記出來,注意這裏不能在回溯過程當中再將標記取消
    for(int i=0;i<4;i++)
    {
        int tr=r+go[i][0];
        int tc=c+go[i][1];
        if(tr>=0&&tr<n&&tc>=0&&tc<m&&!book[tr][tc]&&map[tr][tc]=='.')
        {
            dfs(tr,tc);
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    getchar();
    int t=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
    {
        scanf("%c",&map[i][j]);
        if(map[i][j]=='.')
        t++;
    }
    getchar();
    }
    k=t-k;
    int flag=1;
    for(int i=0;i<n&&flag;i++)
    {
        for(int j=0;j<m&&flag;j++)
    {
        if(map[i][j]=='.')//從第一個.開始搜索
        {
            //book[i][j]=1;
            dfs(i,j);
            flag=0;
        }
        
    }
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
    {
        //printf("%d ",book[i][j]);
        if(map[i][j]=='.'&&!book[i][j])//沒被搜索到的修改
        {
            putchar('X');
        }
        //else if(map[i][j]=='.')
        //putchar('X');
        else
        printf("%c",map[i][j]);
        
    }
    printf("\n");
    }
return 0;
}
View Code

 

E - Justice Rains From Above

 Gym - 101194K 

題意:計算幾何。在一個三維空間裏,法雞在某一點,她會發射攻擊,攻擊是一個圓錐,而後給你幾個敵人的座標,問最多能消滅幾個敵人。

2016-2017ICPC-China final的題目,問學軍的學弟要來的。

你們自行體會一下。

#pragma GCC optimize(2)
#pragma GCC optimize("inline")
#pragma GCC optimize("fast-math")
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <tuple>
#include <cmath>
using namespace std;
 
typedef double real;
const real eps = 1e-12, pi = acos(-1);

inline int fcmp(real x, real y) {
  return fabs(x - y) < eps ? 0 : x < y ? -1 : 1;
}

struct vec {
  real x, y;
  vec operator + (const vec &b) const { return {x + b.x, y + b.y}; }
  vec operator + (void) const { return {x, y}; }
  vec operator - (const vec &b) const { return {x - b.x, y - b.y}; }
  vec operator - (void) const { return {-x, -y}; }
  vec operator * (const vec &b) const
  { return {x * b.x - y * b.y, x * b.y + y * b.x}; }
  vec operator * (real b) const { return {x * b, y * b}; }
  vec operator / (real b) const { return {x / b, y / b}; }
  real dot(const vec &b) const { return x * b.x + y * b.y; }
  real det(const vec &b) const { return x * b.y - y * b.x; }
  real norm(void) const { return x * x + y * y; }
  real len(void) const { return sqrt(norm()); }
  real angle(void) const { return atan2(y, x); }
  vec unit(void) const { return *this / len(); }
  vec perp(void) const { return {-y, x}; }
  bool operator < (const vec &b) const
  { return fcmp(x, b.x) ? x < b.x : fcmp(y, b.y) < 0; }
  bool operator > (const vec &b) const
  { return fcmp(x, b.x) ? x > b.x : fcmp(y, b.y) > 0; }
  bool operator <= (const vec &b) const
  { return fcmp(x, b.x) ? x < b.x : fcmp(y, b.y) <= 0; }
  bool operator >= (const vec &b) const
  { return fcmp(x, b.x) ? x > b.x : fcmp(y, b.y) >= 0; }
  bool operator == (const vec &b) const
  { return fcmp(x, b.x) == 0 && fcmp(y, b.y) == 0; }
  bool operator != (const vec &b) const
  { return fcmp(x, b.x) != 0 || fcmp(y, b.y) != 0; }
};

struct Line {
  vec u, v;
};

struct Circle {
  vec o;
  real r;
};

vec Foot(const Line &l, const vec &p) {
  return l.u + l.v * (l.v.dot(p - l.u) / l.v.norm());
}

Line Bisector(const vec &a, const vec &b) {
  return {(a + b) * 0.5, (b - a).perp()};
}

Line Bisector(const vec &u, const vec &v1, const vec &v2) {
  vec v = v1 + v2 * sqrt(v1.norm() / v2.norm());
  return {u, fcmp(v.norm(), 0) ? v : v1.perp()};
}

tuple<int, vec> Intersection(const Line &l1, const Line &l2) {
  real delta = l1.v.det(-l2.v);
  return fcmp(delta, 0) ?
    make_tuple(1, l1.u + l1.v * ((l2.u - l1.u).det(-l2.v) / delta)) :
    make_tuple(0, vec());
}

tuple<int, vec, vec> Intersection(const Circle &c, const Line &l) {
  vec h = Foot(l, c.o);
  real delta = c.r * c.r - (h - c.o).norm();
  if (fcmp(delta, 0) == 0) {
    return make_tuple(1, h, vec());
  } else if (delta < 0) {
    return make_tuple(0, vec(), vec());
  } else {
    vec v = l.v * sqrt(delta / l.v.norm());
    return make_tuple(2, h + v, h - v);
  }
}

tuple<int, vec, vec> Intersection(const Circle &c1, const Circle &c2) {
  real d2 = (c1.o - c2.o).norm(), d = sqrt(d2);
  int delta = fcmp(c1.r + c2.r + d, max(max(c1.r, c2.r), d) * 2);
  if (delta == 0) {
    return make_tuple(1, c1.o + (c2.o - c1.o) * (c1.r / d), vec());
  } else if (delta < 0) {
    return make_tuple(0, vec(), vec());
  } else {
    real cosa = (c1.r * c1.r - c2.r * c2.r + d2) / (2 * c1.r * d);
    real sina = sqrt(1 - cosa * cosa);
    vec v = (c2.o - c1.o) * (c1.r / d);
    return make_tuple(2, c1.o + v * (vec){cosa, sina},
                      c1.o + v * (vec){cosa, -sina});
  }
}

const int maxn = 1000;

struct vec3 {
  real x, y, z;
  vec3 operator + (const vec3 &b) const { return {x + b.x, y + b.y, z + b.z}; }
  vec3 operator + (void) const { return {x, y, z}; }
  vec3 operator - (const vec3 &b) const { return {x - b.x, y - b.y, z - b.z}; }
  vec3 operator - (void) const { return {-x, -y, -z}; }
  vec3 operator * (real b) const { return {x * b, y * b, z * b}; }
  vec3 operator / (real b) const { return {x / b, y / b, z / b}; }
  real dot(const vec3 &b) const { return x * b.x + y * b.y + z * b.z; }
  real norm(void) const { return x * x + y * y + z * z; }
  real len(void) const { return sqrt(norm()); }
  real angle_xy(void) const { return atan2(y, x); }
  real angle_xz(void) const { return atan2(z, x); }
  vec3 unit(void) const { return *this / len(); }
};

int n;
real alpha;
vec3 point[maxn];

vec3 RotateXY(const vec3 &a, real b) {
  real sinb = sin(b), cosb = cos(b);
  return {a.x * cosb - a.y * sinb, a.x * sinb + a.y * cosb, a.z};
}

vec3 RotateXZ(const vec3 &a, real b) {
  real sinb = sin(b), cosb = cos(b);
  return {a.x * cosb - a.z * sinb, a.y, a.x * sinb + a.z * cosb};
}

int cnt_event;

struct Event {
  real time;
  int delta;
  bool operator < (const Event &b) const {
    return fcmp(time, b.time) ? time < b.time : delta > b.delta;
  }
} ev[maxn * 2];

bool InShape(const vec3 &u) {
  real x = RotateXY(u, -u.angle_xy()).angle_xz();
  return fcmp(x, pi / 2 - alpha) >= 0 && fcmp(x, pi / 2 + alpha) <= 0;
}

real key;

bool InShape2(const vec3 &u) {
  if (u.z < 0) return false;
  return u.z * u.z >= key * (u.x * u.x + u.y * u.y);
}

bool CalcInter(const vec3 &o, real r, real &ans) {
  if (fcmp(r, 0) == 0) {
    return false;
  }
  vec3 v1 = RotateXZ({r, 0, 0}, -alpha);
  vec3 v2 = RotateXZ({0, r, 0}, -alpha);
  if (!InShape(o - v1)) {
    return false;
  }
  int binary_repeat = 20;
  real low = 0, high = pi;
  while (binary_repeat--) {
    real mid = (low + high) * 0.5;
    vec3 u = o + v1 * cos(mid) + v2 * sin(mid);
    if (InShape2(u)) {
      high = mid;
    } else {
      low = mid;
    }
  }
  ans = low;
  return true;
}

real Adjust(real x) {
  while (fcmp(x, 2 * pi) >= 0) {
    x -= 2 * pi;
  }
  while (fcmp(x, 0) < 0) {
    x += 2 * pi;
  }
  return x;
}

int Solve(vec3 ctr) {
  real anxy = -ctr.angle_xy();
  ctr = RotateXY(ctr, anxy);
  real anxz = (pi / 2 - alpha) - ctr.angle_xz();
  ctr = RotateXZ(ctr, anxz);
  cnt_event = 0;
  int init_value = 0;

  for (int i = 0; i < n; ++i) {
    vec3 u = RotateXZ(RotateXY(point[i], anxy), anxz);
    vec3 o = ctr * (ctr.dot(u) / ctr.norm());
    vec3 ou_ = RotateXZ(u - o, alpha);
    vec ou = {ou_.x, ou_.y};
    real init_angle = ou.angle();

    if (InShape(u)) {
      ++init_value;
    }
    real touch_angle;
    if (CalcInter(o, ou.len(), touch_angle)) {
      ev[cnt_event++] = {Adjust(touch_angle - init_angle), 1};
      ev[cnt_event++] = {Adjust(-touch_angle - init_angle), -1};
    }
  }

  sort(ev, ev + cnt_event);
  int ans = 0;
  for (int i = 0; i < cnt_event; ++i) {
    init_value += ev[i].delta;
    ans = max(ans, init_value);
  }
  return ans;
}

int main(void) {
  int t;
  scanf("%d", &t);
  for (int id = 0; id < t; ++id) {
    scanf("%d%lf", &n, &alpha);
    alpha *= pi / 180;
    key = tan(pi / 2 - alpha);
    key *= key;
    int x0, y0, z0;
    scanf("%d%d%d", &x0, &y0, &z0);
    for (int i = 0; i < n; ++i) {
      int x, y;
      scanf("%d%d", &x, &y);
      x -= x0;
      y -= y0;
      point[i] = {(real)x, (real)y, (real)z0};
    }
    int ans = 1;
    for (int i = 0; i < n; ++i) {
      ans = max(ans, Solve(point[i]));
    }
    printf("Case #%d: %d\n", id + 1, ans);
  }
  return 0;
}
View Code

 

F - 缺失的數據範圍

 HDU - 6288 

題意:給你a,b,k,求知足公式n^a*(⌈log2n⌉)^b<=k,的n的最大值。

思路:二分n,向上取整能夠先預處理出2^62,而後直接循環找到b的底數j。要注意精度控制。

#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<string>
#include<math.h>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#define INF 0x3f3f3f3f//3f3f3f3f
typedef long long ll;
using namespace std;
ll a,b,k;
ll s[100]={1};
int check(ll n)
{
    int j=0;
    for(j=0;j<=62;j++)
        if(n<=s[j])break;
    long double t=k;
    for(int i=0;i<b;i++)
    {
        t=t/(long double)j;
        if(t<1.0)return 0;
    }
    for(int i=0;i<a;i++)
    {
        t=t/(long double)n;
        if(t<1.0)return 0;
    }
    return 1;
}
int main()
{
    int ca;
    scanf("%d",&ca);
    for(int i=1;i<=62;i++)
    {
        s[i]=ll(1ll<<i);
    }
    while(ca--)
    {
      scanf("%lld%lld%lld",&a,&b,&k);
      ll l=0,r=k,mid;
      ll ans=0;
      while(r-l>1)
      {
          mid=(l+r)/2;
          if(check(mid))
          {
             l=mid;
          }
          else r=mid-1;
      }
      if(check(r))printf("%lld\n",r);
      else printf("%lld\n",l);
    }
    return 0;
}
View Code

 

G - Triangle

 HDU - 5914 

題意:給你1~n的木棍,問你最少取走幾根能使剩下的木棍不能構成三角形

思路:簽到題。首先,由於給定的n範圍小,因此能夠直接暴力。而後,它是一道找規律的題,爲了達到取走的木棍數最少,因此儘量的取最大的。例舉出來後,會發現剩下的棍子是編號是個斐波那契數列。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<string>
#include<vector>
#include<ctime>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define ll long long
#define MAXN 401000
#define mod ((int)1e9+7)
map<pair<int,int>,int> ma;
int main(){
    int a[10]={1,2,3,5,8,13,21};
    int t;
    scanf("%d",&t);
    int test=1;
    while(t--){
        int n;
        scanf("%d",&n);
        int ans=0;
        for(int i=0;i<=6;i++){
            if(a[i]<=n)
                ans++;
        }
        printf("Case #%d: %d\n",test++,n-ans);
    }
}
View Code

 

 

H - Machine

 ZOJ - 3805 

題意:有n個機器,每一個機器有兩個輸入口輸入原料(上和右)和一個輸出口輸出產物(下),上一個機器的產物能夠做爲下一個機器的原料,且上一個機器的編號必定要大於下一個機器的編號。兩個機器之間能夠用'L'型和'I'型的管子相連,問你全部的機器連起來,最小的寬度是多少

思路:一個父節點的寬度就等於Max(上輸入口子節點的寬度,右輸入口子節點的寬度+1),所以,儘量的把寬度大的子節點鏈接在該節點的上輸入口。

遞歸存入每一個節點的寬度,就能夠獲得根節點的寬度

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cmath>
#include <stack>
#include <cstdlib>
using namespace std;
vector <int> ve[10010];
int dp[10000];
void dfs(int x){
    int len=ve[x].size();
    if(len==0)//若是其沒有子節點
        dp[x]=1;//則寬度只須要記錄它自己所佔的
    else if(len==1){//若是隻有一個
        dfs(ve[x][0]);
        dp[x]=dp[ve[x][0]];//該節點寬度爲其子節點寬度(即放該節點的上面)
    }
    else{//最多就兩個子節點
        int a,b;
        dfs(ve[x][0]);
        dfs(ve[x][1]);
        a=dp[ve[x][0]];
        b=dp[ve[x][1]];
        if(a==b){//若是兩個子節點的寬度相等,那麼該節點寬度爲其中一個放在該節點右邊的子節點的寬度+其自己所佔的
            dp[x]=a+1;
        }
        else{//就把寬度值更大的放在該節點的上面,小的放該節點的右邊。該節點的寬度即寬度值更大的子節點的寬度
            dp[x]=max(a,b);
        }
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n)){
        for(int i=0;i<=n;i++)
            ve[i].clear();
        for(int i=2;i<=n;i++){
            int a;
            scanf("%d",&a);
            ve[a].push_back(i);//存該節點的子節點
        }
        dfs(1);
        printf("%d\n",dp[1]);
    }
}
View Code

 

 

 

I - Nastya Is Buying Lunch

 CodeForces - 1136D 

題意:給你一個大小爲n的排列好的數組,m對二元組(x,y),若是x在y前面且x和y相鄰,則可使x和y交換位置,問你最後一數最多能往前移動幾步

思路:模擬交換過程。若是最後一個數能往前移,前面一定會有一個數和它有對應的二元組,所以找到那個區間,再模擬交換過程,查看是否能前移。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<string>
#include<vector>
#include<ctime>
#include<stack>
using namespace std;
#define inf 0x3f3f3f3f
#define mm(a,b) memset(a,b,sizeof(a))
#define ll long long
#define MAXN 401000
#define mod ((int)1e9+7)
int a[MAXN];
map<pair<int,int>,int> ma;
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    for(int i=0;i<m;i++){
        int u,v;
        scanf("%d %d",&u,&v);
        ma[make_pair(u,v)]=1;//標記全部能交換的二元組
    }
    int last=n-1;
    for(int i=n-2;i>=0;i--){//從倒數第二個數開始往前遍歷
        if(ma[make_pair(a[i],a[last])]){//若是存在一個數能與最後一個數交換,則模擬交換區間內的元素
            int j;
            for(j=i;j<last;j++){
                if(ma[make_pair(a[j],a[j+1])]){
                    swap(a[j],a[j+1]);
                }
                else
                    break;
            }
            if(j==last){//每次移動成功的話,就把最後一個數向前移一位,避免繼續遍歷時遇到後面已經交換過的數。
                last--;
            }
        }
    }
    printf("%d\n",n-1-last);
}
View Code

 

 

J - Easy billiards

 ZOJ - 3761 

 題意:給你n個球的座標,球能夠朝{ 上,下,左,右 }中有另外一個球的方向運動,並經過撞擊另外一個球使本身停下,被撞擊的球沿着這個方向繼續運動,若是這個方向上沒有其餘的球,被撞擊的球將消失。

求最後最少能剩下幾個球,並輸出他們撞擊的方向

思路:將能夠互相撞擊的球構成一棵樹,從而變成了森林,最少剩下的球的數量就是樹的數量,能夠經過並查集求數量。(不用並查集也能夠,先dfs,用vector存下撞擊路徑便可)

輸出路徑能夠經過dfs,每次撞擊都先由子節點撞擊父節點

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<set>
 8 #include<map>
 9 #include<string>
10 #include<vector>
11 #include<ctime>
12 #include<stack>
13 using namespace std;
14 #define inf 0x3f3f3f3f
15 #define mm(a,b) memset(a,b,sizeof(a))
16 #define ll long long
17 #define MAXN 2010
18 #define MAXM 1000010
19 #define mod 998244353
20 int n, p[MAXN];
21 struct node {
22     int x, y;
23 }a[MAXN];
24 int find(int x) {
25     return p[x] == -1 ? x : p[x] = find(p[x]);
26 }
27 void join(int x, int y) {
28     int a = find(x), b = find(y);
29     if (a != b) {
30         p[a] = b;
31     }
32 }
33 int head[MAXN], v[MAXM], ne[MAXM];
34 int vis[MAXN];
35 int id;
36 void addEdge(int x, int y) {
37     v[++id] = y;
38     ne[id] = head[x];
39     head[x] = id;
40 }
41 
42 void dfs(int u, int fa) {
43     vis[u] = 1;
44     for (int i = head[u]; i != -1; i = ne[i])
45     {
46         int now = v[i];
47         if (!vis[now])
48             dfs(now, u);
49     }
50     if (fa != -1)
51     {
52         printf("(%d, %d) ", a[u].x, a[u].y);
53         if (a[fa].x == a[u].x)
54         {
55             if (a[u].y < a[fa].y)
56                 puts("UP");
57             else puts("DOWN");
58         }
59         else
60         {
61             if (a[u].x < a[fa].x) puts("RIGHT");
62             else puts("LEFT");
63         }
64     }
65 }
66 
67 int main() {
68     while (~scanf("%d", &n))
69     {
70         mm(p, -1);
71         mm(head, -1);
72         mm(vis, 0);
73         id = 0;
74         for (int i = 0; i < n; ++i)
75             scanf("%d%d", &a[i].x, &a[i].y);
76         for (int i = 0; i < n; ++i)
77         {
78             for (int j = i + 1; j < n; ++j)
79             {
80                 if (a[i].x == a[j].x || a[i].y == a[j].y)
81                 {
82                     addEdge(i, j);
83                     addEdge(j, i);
84                     join(i, j);
85                 }
86             }
87         }
88         //計算連通塊數量
89         int ans = 0;
90         for (int i = 0; i < n; ++i)
91             if (p[i] == -1) ans++;
92         printf("%d\n", ans);
93         for (int i = 0; i < n; ++i)
94         {
95             if (p[i] == -1) dfs(i, -1);
96         }
97     }
98 }
View Code

 

 

K - What Kind of Friends Are You?

 ZOJ - 3960 

題意:有q個問題和n個詢問,告訴你第i個問題那些人能夠回答(1<=i<=q),而後第j個詢問告訴你這我的能回答哪些問題,若是你能經過他回答的問題猜出他是誰,就輸出他的名字,不然輸出"Let's go to the  library!!"

思路:經過二進制保存每一個人回答的問題,若是x能回答第i個問題,sum[x]+=1<<i

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<set>
 8 #include<map>
 9 #include<string>
10 #include<vector>
11 #include<ctime>
12 #include<stack>
13 using namespace std;
14 #define inf 0x3f3f3f3f
15 #define mm(a,b) memset(a,b,sizeof(a))
16 #define ll long long
17 #define MAXN 2010
18 #define MAXM 1000010
19 int n, q;
20 map<string, int>m;
21 map<int, string>ans;
22 
23 int main()
24 {
25     int t;
26     int k, x;
27     string s;
28     scanf("%d", &t);
29     map<string, int>::iterator it;
30     while (t--)
31     {
32         m.clear();
33         ans.clear();
34         scanf("%d%d", &n, &q);
35         scanf("%d", &k);
36         for (int i = 0; i < k; ++i)
37         {
38             getchar();
39             cin >> s;
40             m[s] = 0;
41         }
42         for (int i = 0; i < q; ++i)
43         {
44             scanf("%d", &k);
45             while (k--)
46             {
47                 getchar();
48                 cin >> s;
49                 m[s] += 1 << i;
50             }
51         }
52         for (it = m.begin(); it != m.end(); it++)
53         {
54             if (ans.count(it->second))
55                 ans[it->second] = "Let's go to the library!!";
56             else
57                 ans[it->second] = it->first;
58         }
59         while (n--)
60         {
61             x = 0;
62             for (int i = 0; i < q; ++i)
63             {
64                 scanf("%d", &k);
65                 if(k) x += 1 << i;
66             }
67             if (ans.count(x))
68                 cout << ans[x] << endl;
69             else
70                 cout << "Let's go to the library!!\n";
71         }
72     }
73 }
View Code

 

 

L - Skyscrapers

CodeForces - 1137A

題意:對於兩條交叉的街道,能夠改變街道上每一個房子的高度,可是要維持同一條街道上房子之間的高矮性,即比他高的仍是比他高,比他矮的仍是比他矮,求這兩條交叉的街道上更改高度後最高的房子的高度。給你n*m條交叉的街道,對於每一個交叉點求出這兩條交叉的街道上更改高度後最高的房子的高度。

思路:ans[i][j] = 1 + max(i街道上比交叉點矮的不一樣高度房子數,j街道上比交叉點矮的不一樣高度房子數)+max(i街道上比交叉點高的不一樣高度房子數,j街道上比交叉點高的不一樣高度房子數)

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<set>
 8 #include<map>
 9 #include<string>
10 #include<vector>
11 #include<ctime>
12 #include<stack>
13 using namespace std;
14 #define inf 0x3f3f3f3f
15 #define mm(a,b) memset(a,b,sizeof(a))
16 #define ll long long
17 #define MAXN 1010
18 #define mod 998244353
19 int n, a[MAXN][MAXN], m;
20 int ma1[MAXN][MAXN], mi1[MAXN][MAXN];
21 int ma2[MAXN][MAXN], mi2[MAXN][MAXN];
22 vector<int>v;
23 int main()
24 {
25     scanf("%d%d", &n, &m);
26     for (int i = 0; i < n; ++i)
27     {
28         for (int j = 0; j < m; ++j)
29             scanf("%d", &a[i][j]);
30     }
31     for (int i = 0; i < n; ++i)
32     {
33         v.clear();
34         for (int j = 0; j < m; ++j)
35             v.push_back(a[i][j]);
36         sort(v.begin(), v.end());
37         int end = unique(v.begin(), v.end()) - v.begin();
38         for (int j = 0; j < m; ++j)
39         {
40             mi1[i][j] = (int)(lower_bound(v.begin(), v.begin() + end, a[i][j]) - v.begin());
41             ma1[i][j] = end - mi1[i][j] - 1;
42         }
43     }
44     for (int i = 0; i < m; ++i)
45     {
46         v.clear();
47         for (int j = 0; j < n; ++j)
48             v.push_back(a[j][i]);
49         sort(v.begin(), v.end());
50         int end = unique(v.begin(), v.end()) - v.begin();
51         for (int j = 0; j < n; ++j)
52         {
53             mi2[j][i] = (int)(lower_bound(v.begin(), v.begin() + end, a[j][i]) - v.begin());
54             ma2[j][i] = end - mi2[j][i] - 1;
55         }
56     }
57     for (int i = 0; i < n; ++i)
58     {
59         for (int j = 0; j < m; ++j)
60             printf("%d ", 1 + max(mi1[i][j], mi2[i][j]) + max(ma1[i][j], ma2[i][j]));
61         printf("\n");
62     }
63 }
View Code
相關文章
相關標籤/搜索