【FJWC】day2简要题解

博客主要介绍了FJWC比赛第二天的三个题目解题思路:1. 构造三叉树解决直径问题,时间复杂度为O(n^2);2. 定价问题,利用特殊数据结构维护连续区间,暴力解决方案;3. 排序问题,通过模拟算法和观察序列变化,使用线段树维护逆序对,注意细节和时间安排。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sro fjzzq2002

1.直径

xjb构造三叉树一定有解
时间复杂度O(n2)O(n^2)O(n2)

#include<bits/stdc++.h>
using namespace std;
const int N=5005;

int k,n,a,b,c;
int u[N],v[N],tot,pre;

inline void fd()
{
   for(a=1;a<5000;++a)
	 for(b=a;a+b<5000 && a*b<=k;++b) 
	   if((k-a*b)%(a+b)==0){
	     if((k-a*b)/(a+b)<=5000-a-b-4) 
		   {c=(k-a*b)/(a+b);
		   return;}	
	   }
}

int main(){
	freopen("diameter.in","r",stdin);
	freopen("diameter.out","w",stdout);
	int i,j;
	scanf("%d",&k);fd();
    u[++tot]=(n=1);v[tot]=++n;pre=n;
	for(i=1;i<=a;++i){u[++tot]=pre;v[tot]=++n;}
	u[++tot]=1;v[tot]=++n;pre=n;
	for(i=1;i<=b;++i){u[++tot]=pre;v[tot]=++n;}
	if(c){
		u[++tot]=1;v[tot]=++n;pre=n;
		for(i=1;i<=c;++i) {u[++tot]=pre;v[tot]=++n;}
	}
    printf("%d\n",n);
    for(i=1;i<n;++i) printf("%d %d 1\n",u[i],v[i]);
    fclose(stdin);fclose(stdout);
    return 0;
}

2.定价

用你喜爱的数据结构维护:

  • 每个二进制位上1出现的连续区间
  • 在位置iii找到最高的一位jjj满足第i−1i-1i1位置这位为1且位置iii这位不能再为1,并查找更高位最近的一个可以变成1的0,并把所有小的位变成0。

似乎可以暴力艹标算。
代码咕咕咕。

std:

#include <bits/stdc++.h>

using namespace std;

const int md = 1e9 + 7;

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

inline int mul(int x, int y) {
  return (long long) x * y % md;
}

inline int power(int x, int y) {
  int res = 1;
  for (; y; y >>= 1, x = mul(x, x)) {
    if (y & 1) {
      res = mul(res, x);
    }
  }
  return res;
}

template<typename T>
class heap {
 private:
  priority_queue<T> p, q;

 public:
  inline void push(T x) {
    p.push(x);
  }

  inline void pop(T x) {
    q.push(x);
  }

  inline void clear() {
    while (!p.empty()) {
      p.pop();
    }
    while (!q.empty()) {
      q.pop();
    }
  }

  inline bool empty() {
    return p.size() == q.size();
  }

  inline T top() {
    while (!q.empty() && p.top() == q.top()) {
      p.pop();
      q.pop();
    }
    return p.top();
  }
};

#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}

int main() {
  FO(price)
  ios::sync_with_stdio(false);
  cin.tie(0);
  int n, m, q;
  cin >> n >> m >> q;
  unordered_map<int, set<pair<int, int>>> columns;
  vector<set<int>> board(n);
  int last = 0;
  while (q--) {
    int type;
    cin >> type;
    if (type == 1) {
      int x, y;
      cin >> x >> y;
      y = m - y; --x;
      if (board[x].count(y)) {
        board[x].erase(y);
        auto it = columns[y].lower_bound(make_pair(x, 0));
        if (it == columns[y].end() || it->first != x) {
          --it;
        }
        int l = it->first, r = it->second;
        columns[y].erase(it);
        if (l != x) {
          columns[y].insert(make_pair(l, x - 1));
        }
        if (r != x) {
          columns[y].insert(make_pair(x + 1, r));
        }
      } else {
        board[x].insert(y);
        int l = x, r = x;
        {
          auto it = columns[y].lower_bound(make_pair(x, x));
          while (it != columns[y].end() && it->first == r + 1) {
            r = it->second;
            columns[y].erase(it++);
          }
        }
        {
          auto it = columns[y].lower_bound(make_pair(x, x));
          if (it != columns[y].begin()) {
            --it;
            while (it->second == l - 1) {
              l = it->first;
              if (it == columns[y].begin()) {
                columns[y].erase(it);
                break;
              }
              columns[y].erase(it--);
            }
          }
        }
        columns[y].insert(make_pair(l, r));
      }
    } else {
      heap<pair<int, int>> candidates;
      set<int> cur;
      int ans = 0;
      int sum = 0;
      for (int i = 0; i < n; ++i) {
        int largest = -1;
        while (!candidates.empty() && -candidates.top().first == i) {
          largest = max(largest, candidates.top().second);
          candidates.pop(candidates.top());
        }
        bool not_found = false;
        while (true) {
          auto it = board[i].upper_bound(largest);
          if (it == board[i].end()) {
            not_found = true;
            break;
          }
          while (!cur.empty() && *cur.begin() < *it) {
            int x = i, y = *cur.begin();
            sub(sum, power(2, y));
            cur.erase(y);
            --x;
            auto it = columns[y].lower_bound(make_pair(x, 0));
            if (it == columns[y].end() || it->first != x) {
              --it;
            }
            if (it->second != x) {
              candidates.pop(make_pair(-it->second - 1, y));
            }
          }
          if (cur.empty() || *cur.begin() != *it) {
            int x = i, y = *it;
            add(sum, power(2, y));
            cur.insert(y);
            auto it = columns[y].lower_bound(make_pair(x, 0));
            if (it == columns[y].end() || it->first != x) {
              --it;
            }
            candidates.push(make_pair(-it->second - 1, y));
            break;
          } else {
            largest = *it;
          }
        }
        if (not_found) {
          ans = -1;
          break;
        }
        add(ans, sum);
      }
      cout << ans << "\n";
      if (ans != -1) {
        last = ans;
      }
    }
  }
  return 0;
}


3.排序

考虑模拟出这个算法进行kkk轮(即外层的i循环到k)时的序列,之后再暴力模拟零散的步。

打表找规律,观察每个数位置的变化:

1 9 5 4 8 7 2 3 6 
1 2 9 5 8 7 4 3 6 
1 2 3 9 8 7 5 4 6 
1 2 3 4 9 8 7 5 6 
1 2 3 4 5 9 8 7 6 
1 2 3 4 5 6 9 8 7 
1 2 3 4 5 6 7 9 8 
1 2 3 4 5 6 7 8 9 
1 2 3 4 5 6 7 8 9 

变化规律(设viv_ivi表示数字iii位置前面&lt;i&lt;i<i的数字个数):

viv_iviiii位置保持不动,从第vi+1v_i+1vi+1到第i−1i-1i1iii逐个遍历它后面所有比它小的数的位置,第iii轮回归位置iii后保持不动。

其实也很好证明:

在第iii轮时,维护从位置iii开始下表递增的递减序列。
iii轮结束时,数列整体的变换相当于递减序列中所有数在位置上循环右移了一位(末端的iii回到了位置iii)

而前viv_iviiii前面都有比它小的数,不可能进入递减序列,所以位置不动。
同时在这viv_ivi轮变化中,iii位置后面的数和iii的相对大小保持不变,而iii由于前面没有比它小的数所以会一直呆在递减序列中直到回到位置iii并在此之前逐个右移遍历后面所有比它小的数的位置。

线段树维护逆序对即可。

ai=n−i+1a_i=n-i+1ai=ni+1的特判中
j=i+1j=i+1j=i+1写成了j=i+2j=i+2j=i+2,成功挂掉10分。。。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
const int N=1e6+10;

int n,a[N],m,cnt[35],cot,ans;
int bn[35],mst[35];

char cp,buf[N],wbuf[N],os[100];
int p1,p2,p3;
inline char gc(){
	if(p1==p2) p1=0,p2=fread(buf,1,N,stdin);
	return p1==p2?EOF:buf[p1++];
}

inline void rd(int &x)
{
	cp=getchar();x=0;
	for(;!isdigit(cp);cp=getchar());
	for(;isdigit(cp);cp=getchar()) x=x*10+(cp^48);
}

inline void wchar(char x)
{
	if(p3==N) fwrite(wbuf,1,N,stdout),p3=0;
	wbuf[p3++]=x;
}

inline int fd(int x)
{
	if(!x) return -1;
	int l=0,r=30,mid,y;
	for(;l<=r;){mid=(l+r)>>1;(x>=(1<<mid))?(l=(y=mid)+1):(r=mid-1);}
	return y;
}

void chg(int x,int y,int op)
{
	x=fd(x);if(x==-1) return;
	if(op){
		if((a[y]>>x)&1) bn[x]++;else{mst[x]++;ans|=(1<<x);}
	}else{
		if((a[y]>>x)&1) bn[x]--;else{mst[x]--;if((!mst[x])) ans^=(1<<x);}
	}
	
}

inline void prit()
{
	int i;
	for(i=0;i<=30;++i) if((bn[i] && mst[i])) break;
	if(i<=30){
	  wchar('-');wchar('1');
	}
	else{
		int x=ans,re=0;
		for(;(!re)||(x);x/=10) os[++re]='0'+(x%10);
		for(;re;--re) wchar(os[re]);
	}
	if(m>1) wchar('\n');
}

int main(){
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);
	int i,x,y,l,r,mid;
	rd(n);for(i=1;i<=n;++i) rd(a[i]);
	for(i=2;i<=n;++i) chg(a[i-1]^a[i],i,1);
	rd(m);m++;prit();m--;
	for(;m;--m){
		rd(x);rd(y);
		if(x>1) chg(a[x]^a[x-1],x,0);
		if(x<n) chg(a[x]^a[x+1],x+1,0);
		a[x]=y;
		if(x>1) chg(a[x]^a[x-1],x,1);
		if(x<n) chg(a[x]^a[x+1],x+1,1);
		prit();
	}
	if(p3) fwrite(wbuf,1,p3,stdout);
	fclose(stdin);fclose(stdout);
	return 0;
}


总结

T3还是细节问题,且浪费了很久找了许多无用的性质(没有直接打表)

考试的时候前半段时间安排不紧凑,导致做完T1再肝了T3后T2连暴力都没打。
实际上有几位人赢都T2都暴力艹标算 AC了…十分不划算

所以以后遇到时限5s+的题都可以信仰暴力?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值