1. 程式人生 > 其它 >2017ICPC瀋陽部分簡要題解

2017ICPC瀋陽部分簡要題解

技術標籤:# ICPC

B - Bridge

橋等價於不在環內的邊。那麼可以統計維護環內邊的個數,容斥一下得出橋的個數。

線段樹維護區間內豎邊的個數,最左豎邊的位置,最右豎邊的位置。

set維護連續的上下都有橫邊的區間的左端點和右端點。

寫了200行。

沒搞懂為什麼其他題解都是multiset。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
set<pii> s ;
int n , m ;
int tot , num ;
//點修改,區間min,max,sum
int sum[maxn << 2] ;
int mn[maxn << 2] ;
int mx[maxn << 2] ;
int cnt[maxn] ;
int ls(int x)
{
   return x << 1 ;
}
int rs(int x)
{
   return x << 1 | 1 ;
}
void push_up(int id)
{
    sum[id] = sum[ls(id)] + sum[rs(id)] ;
    mn[id] = min(mn[ls(id)] , mn[rs(id)]) ;
    mx[id] = max(mx[ls(id)] , mx[rs(id)]) ;
}
void build(int id , int l , int r)
{
   if(l == r){ sum[id] = 1 , mn[id] = mx[id] = l ; return ;}
   int mid = (l + r) >> 1 ;
   build(ls(id) , l , mid) ;
   build(rs(id) , mid + 1 , r) ;
   push_up(id) ;
}
void add(int id , int l , int r , int x)
{
   int mid = (l + r) / 2 ;
   if(l == r && l == x){ sum[id] = 1 , mn[id] = mx[id] = l ; return ;}
   if(x <= mid)  add(ls(id) , l , mid , x) ;
   else  add(rs(id) , mid + 1 , r , x) ;
   push_up(id) ;
}
void del(int id , int l , int r , int x)
{
   int mid = (l + r) / 2 ;
   if(l == r && l == x){ sum[id] = 0 , mn[id] = inf , mx[id] = 0 ; return ;}
   if(x <= mid)  del(ls(id) , l , mid , x) ;
   else  del(rs(id) , mid + 1 , r , x) ;
   push_up(id) ;
}
int query_sum(int id , int l , int r , int x , int y)
{
   int ans = 0 ;
   int mid = (l + r) / 2 ;
   if(y < x)  return 0 ; //不合法的詢問
   if(x <= l && r <= y)  return sum[id] ;
   if(x <= mid)  ans += query_sum(ls(id) , l , mid , x , y) ;
   if(y > mid)  ans += query_sum(rs(id) , mid + 1 , r , x , y) ;
   return ans ;
}
int query_max(int id , int l , int r , int x , int y)
{
   int ans = 0 ;
   int mid = (l + r) / 2 ;
   if(x <= l && r <= y)  return mx[id] ;
   if(x <= mid)  ans = max(ans , query_max(ls(id) , l , mid , x , y)) ;
   if(y > mid)  ans = max(ans , query_max(rs(id) , mid + 1 , r , x , y)) ;
   return ans ;
}
int query_min(int id , int l , int r , int x , int y)
{
   int ans = inf ;
   int mid = (l + r) / 2 ;
   if(x <= l && r <= y)  return mn[id] ;
   if(x <= mid)  ans = min(ans , query_min(ls(id) , l , mid , x , y)) ;
   if(y > mid)  ans = min(ans , query_min(rs(id) , mid + 1 , r , x , y)) ;
   return ans ;
}
void init()
{
    tot = 3 * n - 2 ;
    num = 3 * n - 2 ;
    cl(s) ;
    s.insert({1 , n}) ;
    build(1 , 1 , n) ;
    rep(i , 1 , n - 1)  cnt[i] = 2 ;
}
int cal(int l , int r)
{
    int sum = query_sum(1 , 1 , n , l , r) ;
    int mx = query_max(1 , 1 , n , l , r) ;
    int mn = query_min(1 , 1 , n , l , r) ;
    if(sum <= 1)  return 0 ;
    return sum + (mx - mn) * 2 ;
}
void add_row(int x0 , int y0)
{
    cnt[y0] ++ ;
    tot ++ ;
    if(cnt[y0] == 2)
    {
        auto it = s.lower_bound({y0 + 1 , 0}) ;
        int l2 = (*it).fi ;
        int r2 = (*it).se ;
        it -- ;
        int l1 = (*it).fi ;
        int r1 = (*it).se ;
        num -= cal(l1 , r1) ;
        num -= cal(l2 , r2) ;
        s.erase({l1 , r1}) ;
        s.erase({l2 , r2}) ;
        s.insert({l1 , r2}) ;
        num += cal(l1 , r2) ;
    }
}
void add_col(int y0)
{
    tot ++ ;
    auto it = s.lower_bound({y0 + 1 , 0}) ;
    it -- ;
    int l = (*it).fi ;
    int r = (*it).se ;
    num -= cal(l , r) ;
    add(1 , 1 , n , y0) ;
    num += cal(l , r) ;    
}
void del_row(int x0 , int y0)
{
    cnt[y0] -- ;
    tot -- ;
    if(cnt[y0] == 1)
    {
        auto it = s.lower_bound({y0 + 1 , 0}) ;
        it -- ;
        int l1 = (*it).fi ;
        int r2 = (*it).se ;
        int r1 = y0 ;
        int l2 = y0 + 1 ;
        num -= cal(l1 , r2) ;
        num += cal(l1 , r1) ;
        num += cal(l2 , r2) ;
        s.erase(it) ;
        s.insert({l1 , r1}) ;
        s.insert({l2 , r2}) ;
    }
}
void del_col(int y0)
{
    tot -- ;
    auto it = s.lower_bound({y0 + 1 , 0}) ;
    it -- ;
    int l = (*it).fi ;
    int r = (*it).se ;
    num -= cal(l , r) ;
    del(1 , 1 , n , y0) ;
    num += cal(l , r) ;
}
int main()
{
    ios ;
    int T ;
    cin >> T ;
    while(T --)
    {
        cin >> n >> m ;
        init() ;
        while(m --)
        {
            int op , x0 , y0 , x1 , y1 ;
            cin >> op >> x0 >> y0 >> x1 >> y1 ;
            if(op == 1)
            {
                if(x0 == x1)  add_row(x0 , min(y0 , y1)) ;
                else  add_col(y0) ;
            }
            else
            {
                if(x0 == x1)  del_row(x0 , min(y0 , y1)) ;
                else  del_col(y0) ;
            }
            cout << tot - num << '\n' ;
        }
    }
    return 0 ;
}

C - Empty Convex Polygons

首先列舉左下角的點Odp[i][j]表示以Oi,ij為最後兩條邊的滿足題意的最大凸多邊形的面積。

轉移方程:dp[i][j]=max(dp[i][j],triangle\_area(O,i,j)+dp[j][k])

複雜度是O(n^4)

我又寫了200多行。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 100 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int n ;
db dp[maxn][maxn] ;
int sgn(db x)
{
    if(x < -eps) return -1 ;  else if (x > eps)  return 1 ;  else return 0 ;
}
void print(int num , db x)
{
    cout << fixed << setprecision(num) << x << '\n' ;
}
struct point
{
    db x , y ;
    point(){}
    point(db _x , db _y)
    {
        x = _x , y = _y ;
    }
    point operator + (const point& s) const
    {
        return point(x + s.x , y + s.y) ;
    }
    point operator - (const point& s) const
    {
        return point(x - s.x , y - s.y) ;
    }
    point operator * (const db& k) const
    {
        return point(x * k , y * k) ;
    }
    point operator / (const db& k) const
    {
        return point(x / k , y / k) ;
    }
    db get_angle()//極角
    {
        return atan2(y , x) ;
    } 
    bool operator == (point b) const
    {
        return sgn(x - b.x) == 0 && sgn(y - b.y) == 0 ;
    }
    bool operator < (point b)const
    {
        return sgn(x - b.x) == 0 ? sgn(y - b.y) < 0 : x < b.x ;
    }
    db operator ^(const point &b) const //向量叉積
    {
        return x * b.y - y * b.x ;
    }
    db operator *(const point &b) const //向量點積
    {
        return x * b.x + y * b.y ;
    }
    db sqr(db x)
    {
        return x * x ;
    }
    db len() //與原點的距離
    {
        return sqrt(sqr(x) + sqr(y)) ;
    }
    db dis(point p) //返回兩點間的距離
    {
        return sqrt(sqr(x - p.x) + sqr(y - p.y)) ;
    }
    db rad(point a , point b) //向量p->a和p->b的夾角
    {
        point p = *this ;
        return fabs(atan2(fabs((a - p) ^ (b - p)) , (a - p) * (b - p))) ;
    }
    point trunc(db r) //化為長度為r的向量
    {
        db l = len() ;
        if(!sgn(l))  return *this ;
        r /= l ;
        return point(x * r , y * r) ;
    }
    point rot_left() //逆時針旋轉90度
    {
        return point(-y , x) ;
    }
    point rot_right() //順時針旋轉90度
    {
        return point(y , -x) ;
    }
    point rotate(point p , db angle) //繞a點逆時針旋轉angle
    {
        point v = (*this) - p ;
        db c = cos(angle) , s = sin(angle) ;
        return point(p.x + v.x * c - v.y * s , p.y + v.x * s + v.y * c) ; 
    }
} p[maxn] ;
struct line
{
    point s , e ;
    line(){}
    line(point _s , point _e)
    {
        s = _s , e = _e ;
    }
    db len()
    {
        return s.dis(e) ;
    }
    void adjust()
    {
        if(e < s)  swap(s , e) ;
    }
    db dis_point_to_line(point p) //點a到直線的距離
    {
        return fabs((p - s) ^ (e - s)) / len() ;
    }
    db dis_point_to_seg(point p) //點a到線段的距離
    {
        if(sgn((p - s) * (e - s)) < 0 || sgn((p - e) * (s - e)) < 0)  return min(p.dis(s) , p.dis(e)) ;
        else  return dis_point_to_line(p) ;
    }
    pair<point,int> operator &(const line &b) const //直線相交求交點
    {
        point res = s ;
        if(sgn((s - e) ^ (b.s - b.e)) == 0)
        {
            if(sgn((b.s - s) ^ (b.e - s)) == 0)  return make_pair(res , 0) ; //兩直線重合
            else  return make_pair(res , 1) ; //兩直線平行
        }
        db t = ((s - b.s) ^ (b.s - b.e)) / ((s - e) ^ (b.s - b.e)) ;
        res.x += (e.x - s.x) * t ;
        res.y += (e.y - s.y) * t ;
        return  make_pair(res , 2) ; //有交點
    }
    int relation(point p) //點和有向直線關係
    {
        //正負需要考慮清楚
        int c = sgn((p - s) ^ (e - s)) ;//直線認為是有向直線s->e,根據需求調整直線方向
        if(c < 0)  return 1 ; //1 在左側
        else if(c > 0)  return 2 ; //2 在右側
        else  return 3 ; //3 在直線上
    }
    bool point_on_seg(point p)
    {
        return sgn((p - s) ^ (e - s)) == 0 && sgn((p - s) * (p - e)) <= 0 ;
    }
} ;
bool can(int i , int j)
{
    if(sgn(p[j].x - p[i].x) < 0)  return 0 ;
    if(sgn(p[j].x - p[i].x) == 0 && sgn(p[j].y - p[i].y) < 0)  return 0 ;
    return 1 ;
}
bool cmp(point a , point b)
{
    db p = a.get_angle() , q = b.get_angle() ;
    if(sgn(p - q) != 0)  return p < q ;
    return a.x < b.x ;
}
double cal(double x1 , double y1 , double x2 , double y2 , double x3 , double y3)
{
    return fabs(x1 * y2 - y1 * x2 + x2 * y3 - y2 * x3 + x3 * y1 - y3 * x1) / 2 ;
}
db cal1(point p1 , point p2 , point p3)
{
    return cal(p1.x , p1.y , p2.x , p2.y , p3.x , p3.y) ;
}
bool left(point p , point a , point b)
{
    point p1 = p - a ;
    point p2 = b - a ;
    return sgn(p1 ^ p2) < 0 ;
}
bool In(point a , point b , point c , point k)
{
    return left(k , a , b) && left(k , b , c) && left(k , c , a) ;
}
bool in(point o , point i , point j)
{
    rep(k , 1 , n)   if(In(o , i , j , p[k]))  return 1 ;
    return 0 ;
}
bool ok(point o , point i , point j , point k)
{
    point p1 = j - i ;
    point p2 = k - j ;
    return sgn(p1 ^ p2) > 0 ;
}
bool online(point o , point j)
{
    if((o.dis(j)) > 0)
    {
        point p1 = j - o ;
        rep(s , 1 , n)
        {
            point p2 = p[s] - o ;
            if(sgn(o.dis(p[s])) > 0 && sgn(o.dis(j)) > 0 && sgn(p1 ^ p2) == 0 && sgn(o.dis(p[s]) - o.dis(j)) < 0)  return 1 ;
        }
    }
    return 0 ;
}
db solve(int o)
{
    //以(x_o,y_o)為左下角的點
    db res = 0 ;
    rep(i , 0 , n)  rep(j , 0 , n)  dp[i][j] = -1e10 ;
    vector<point> v ;
    rep(i , 1 , n)  if(i != o && can(o , i))  v.pb(p[i] - p[o]) ;
    sort(all(v) , cmp) ;
    reverse(all(v)) ;
    //for(auto u : v)  ddebug(u.x , u.y) ;
    point oo = (point){0.0 , 0.0} ;
    rep(i , 0 , sz(v) - 1)  rep(j , 0 , i - 1)
    {
        if(in(p[o] , p[o] + v[i] , p[o] + v[j]))  continue ;
        db s = cal1(oo , v[i] , v[j]) ;
        dp[i][j] = s ;
        rep(k , 0 , j - 1)  if(ok(oo , v[i] , v[j] , v[k]) && !online(p[o] , p[o] + v[j]))  dp[i][j] = max(dp[i][j] , s + dp[j][k]) ;
        res = max(res , dp[i][j]) ;
        // ddebug(i , j) ;
        // debug(dp[i][j]) ;
    }
    return res ;
}
int main()
{
    ios ;
    int T ;
    cin >> T ;
    while(T --)
    {
        cin >> n ;
        rep(i , 1 , n)  cin >> p[i].x >> p[i].y ;
        db ans = 0 ;
        rep(i , 1 , n)  ans = max(ans , solve(i)) ;
        print(1 , ans) ;
    }
    return 0 ;
}

F - Heron and His Triangle

打表發現符合題意的t滿足下式,其中f(i)表示第i個滿足題意的t

f(i)=f(i-1)*4+f(i-2)

搞一個大數就好了。

不卡常,很友好。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
struct bign
{
    int d[105], len;
    void clean() { while(len > 1 && !d[len-1]) len--; }
    bign()          { memset(d, 0, sizeof(d)); len = 1; }
    bign(int num)   { *this = num; }
    bign(char* num) { *this = num; }
    bign operator = (const char* num){
        memset(d, 0, sizeof(d)); len = strlen(num);
        for(int i = 0; i < len; i++) d[i] = num[len-1-i] - '0';
        clean();
        return *this;
    }
    bign operator = (int num){
        char s[105]; sprintf(s, "%d", num);
        *this = s;
        return *this;
    }
  
    bign operator + (const bign& b){
        bign c = *this; int i;
        for (i = 0; i < b.len; i++){
            c.d[i] += b.d[i];
            if (c.d[i] > 9) c.d[i]%=10, c.d[i+1]++;
        }
        while (c.d[i] > 9) c.d[i++]%=10, c.d[i]++;
        c.len = max(len, b.len);
        if (c.d[i] && c.len <= i) c.len = i+1;
        return c;
    }
    bign operator - (const bign& b){
        bign c = *this; int i;
        for (i = 0; i < b.len; i++){
            c.d[i] -= b.d[i];
            if (c.d[i] < 0) c.d[i]+=10, c.d[i+1]--;
        }
        while (c.d[i] < 0) c.d[i++]+=10, c.d[i]--;
        c.clean();
        return c;
    }
    bign operator * (const bign& b)const{
        int i, j; bign c; c.len = len + b.len;
        for(j = 0; j < b.len; j++) for(i = 0; i < len; i++)
            c.d[i+j] += d[i] * b.d[j];
        for(i = 0; i < c.len-1; i++)
            c.d[i+1] += c.d[i]/10, c.d[i] %= 10;
        c.clean();
        return c;
    }
    bign operator / (const bign& b){
        int i, j;
        bign c = *this, a = 0;
        for (i = len - 1; i >= 0; i--)
        {
            a = a*10 + d[i];
            for (j = 0; j < 10; j++) if (a < b*(j+1)) break;
            c.d[i] = j;
            a = a - b*j;
        }
        c.clean();
        return c;
    }
    bign operator % (const bign& b){
        int i, j;
        bign a = 0;
        for (i = len - 1; i >= 0; i--)
        {
            a = a*10 + d[i];
            for (j = 0; j < 10; j++) if (a < b*(j+1)) break;
            a = a - b*j;
        }
        return a;
    }
    bign operator += (const bign& b){
        *this = *this + b;
        return *this;
    }
  
    bool operator <(const bign& b) const{
        if(len != b.len) return len < b.len;
        for(int i = len-1; i >= 0; i--)
            if(d[i] != b.d[i]) return d[i] < b.d[i];
        return false;
    }
    bool operator >(const bign& b) const{return b < *this;}
    bool operator<=(const bign& b) const{return !(b < *this);}
    bool operator>=(const bign& b) const{return !(*this < b);}
    bool operator!=(const bign& b) const{return b < *this || *this < b;}
    bool operator==(const bign& b) const{return !(b < *this) && !(b > *this);}
  
    string str() const{
        char s[maxn]={};
        for(int i = 0; i < len; i++) s[len-1-i] = d[i]+'0';
        return s;
    }
} bb[105] ;
istream& operator >> (istream& in, bign& x)
{
    string s;
    in >> s;
    x = s.c_str();
    return in;
}
ostream& operator << (ostream& out, const bign& x)
{
    out << x.str();
    return out;
}
int main()
{
    ios ;
    bb[1] = 4 ;
    bb[2] = 14 ;
    rep(i , 3 , 55)  bb[i] = bb[i - 1] * 4 - bb[i - 2] ;
    int T ;
    cin >> T ;
    while(T --)
    {
        bign a ;
        cin >> a ;
        rep(i , 1 , 55)  
          if(a <= bb[i])
          {
             cout << bb[i] << '\n' ;
             break ;
          }
    }
    return 0 ;
}

G - Infinite Fraction Path

容易發現在起點固定時的路徑是一個非迴圈串和無限迴圈串構成的。

發現在最壞情況下(即n是素數),非迴圈串和1個迴圈節的長度不超過200

然後暴力亂搞就行了。

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5, lim = 300;
int n, d[N], nxt[N], p[N], kase;
char s[N];
void Max(int &x, int y)
{
    int a = x, b = y, cnt = 1;
    while(d[a]==d[b]) 
    {
        a = nxt[a], b = nxt[b];
        ++cnt;
        if(cnt>=min(lim, n)) break;
    }
    if(d[a]<d[b]) x = y;
}
void solve()
{
    scanf("%d%s", &n, s);
    for(int i=0; i<n; i++) d[i] = s[i] - '0';
    for(int i=0; i<n; i++) p[i] = i, nxt[i] = (1ll*i*i+1)%n;
    random_shuffle(p, p+n);
    int mx = p[0];
    for(int i=1; i<n; i++) Max(mx, p[i]);
    printf("Case #%d: ", ++kase);
    for(int i=0; i<n; i++) 
    {
        printf("%d", d[mx]);
        mx = nxt[mx];
    }
    puts("");
}
int main()
{
    int _; scanf("%d", &_);
    while(_--) solve();
    return 0;
}

I - Little Boxes

特判超過long\;long的測例就可以了。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
unsigned long long a[10] ;
int main()
{
    ios ;
    int T ;
    cin >> T ;
    while(T --)
    {
        unsigned long long ans = 0 ;
        rep(i , 1 , 4)  cin >> a[i] ;
        if(a[1] == (1ll << 62) && a[2] == (1ll << 62) && a[3] == (1ll << 62) && a[4] == (1ll << 62))
        {
            cout << "18446744073709551616" << '\n' ;
            continue ;
        }
        else  rep(i , 1 , 4)  ans += a[i] ;
        cout << ans << '\n' ;
    }
    return 0 ;
}

K - Rabbits

答案 = 相鄰兩個兔子間空位長度的和 - min(最左邊兔子和它右邊的相鄰兔子之間的空位長度,最右邊兔子和它左邊的相鄰兔子之間的空位長度)

#include <bits/stdc++.h>
using namespace std;
void solve()
{
	int n; scanf("%d", &n);
	vector<int> a(n);
	for(int &x : a) scanf("%d", &x);
	int ans = 0;
	for(int i=1; i<n; i++) 
		ans += a[i] - a[i-1] - 1;
	printf("%d\n", ans-min(a[1]-a[0]-1, a[n-1]-a[n-2]-1));
}
int main()
{
	int _; scanf("%d", &_);
	while(_--) solve();
	return 0;
}

L - Tree

我們訓練的時候是用拓撲做的。賽後發現有個簡單做法,如果一條邊的左右兩端都有大於等於k個節點,那麼這條邊就可以被計數一次。

#include<bits/stdc++.h>
using namespace std;
#define M 200005
vector<int>G[M];
int stk[M],top,sz[M],du[M]; 
void solve(){
	int n,k;
	scanf("%d %d",&n,&k);
	top=0;
	for(int i=1;i<=n;i++){
		G[i].clear();
		sz[i]=1;
		du[i]=0;
	}
	for(int i=1;i<n;i++){
		int a,b;
		scanf("%d %d",&a,&b);
		G[a].push_back(b);
		G[b].push_back(a); 
		du[a]++;
		du[b]++;
	}
	int dlt=0;
	for(int i=1;i<=n;i++){
		if(du[i]==1)stk[++top]=i;
	}
	for(int i=1;i<=top;i++){
		int x=stk[i];
		if(sz[x]>=k)continue;
		dlt++;
		for(int j=0;j<G[x].size();j++){
			int y=G[x][j];
			if(du[y]==1)continue;
			du[y]--;
			sz[y]+=sz[x];
			if(du[y]==1)stk[++top]=y;
		}
	}
	printf("%d\n",n-1-dlt);
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--)solve();
	return 0;
}

M - Wandering Robots

根據樣例的10/19猜個結論就好了。

每個點賦權值,權值大小是當前點可以被幾個相鄰點所到達(包括自身)。

權值和的比值就是答案。

#include<bits/stdc++.h>
using namespace std;
#define M 200005
map<pair<int,int>,int>mp;
int n,k;
bool check(int x,int y){
	return x>=0&&x<n&&y>=0&&y<n;
}
int kase;
void solve(){
	scanf("%d %d",&n,&k);
	int ans1=(5*n*n+n-4)/2,ans2=5*n*n-4*n;
	mp.clear(); 
	for(int i=1;i<=k;i++){
		int a,b;
		scanf("%d %d",&a,&b);
		int cnt=0;
		if(check(a-1,b)&&!mp[make_pair(a-1,b)]){
			cnt++;
			ans2--;
			if((a-1)+b>=n-1)ans1--;
		}
		if(check(a+1,b)&&!mp[make_pair(a+1,b)]){
			cnt++;
			ans2--;
			if((a+1)+b>=n-1)ans1--;
		}
		if(check(a,b-1)&&!mp[make_pair(a,b-1)]){
			cnt++;
			ans2--;
			if(a+(b-1)>=n-1)ans1--;
		}
		if(check(a,b+1)&&!mp[make_pair(a,b+1)]){
			cnt++;
			ans2--;
			if(a+(b+1)>=n-1)ans1--;
		}
		ans2-=cnt+1;
		if(a+b>=n-1)ans1-=cnt+1;
		mp[make_pair(a,b)]=1;
	}
	int Gcd=__gcd(ans1,ans2);
	printf("Case #%d: %d/%d\n",++kase,ans1/Gcd,ans2/Gcd);
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--)solve();
	return 0;
}