2017-8-30 NOIP冲刺

5 篇文章 0 订阅
3 篇文章 0 订阅

Task 1:锦标赛

题目描述:

给出2^n个数,进行n此操作。每次操作对当前剩下的数两两比较(任意组合都可以),留下较大的那个。现在询问对于每个数,做多可以进行多少操作。

题目分析:

我们可以很显然发现,按照题意进行操作我们可以得到一颗完全二叉树。所以对于一个数a,有b个数小于等于a,那么ans=log2(b)。

Code:

#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;

const int MAXN = 1<<20;

int b, n;
int a[MAXN+5], q[MAXN+5];

int main(){
    scanf("%d",&b), n = 1<<b;
    for(int i = 1; i <= n; ++ i)
        scanf("%d",&a[i]), q[i] = a[i];
    sort(q+1, q+n+1);
    for(int i = 1; i <= n; ++ i){
        int p = upper_bound(q+1, q+n+1, a[i])-q-1;
        printf("%d",log2(p));
        if(i != n) putchar(32);
        else putchar(10);
    }
    return 0;
}

Task 2:不完美值

题目描述:

给出数组a[],区间[l,r]。令xi表示sigma(b) (b|a[i] && b!=a[i])。求sigma(abs(ai-xi)) (l<=i<=r)。

题目分析:

这道题就是裸的求一个数的真因子和。但是考虑到做多有10^7个数,所以不能暴力的对每个数用sqrt(n)的时间来求,这样肯定会T。
所以我们就需要一个线性的算法。
我们定义f[i]表示i的因子和,p是素数且p|i。
所以f[i]=(1+p1+p1^2+……p1^k1)*(1+p2+p2^2+……p2^k2)*……*(1+pn+pn^2+……pn^kn)。
这样我们就可以用类似筛法来求了。

Code:

#include <cstdio>
#define abs(v) ((v)<0 ? -(v):(v))
int l, r;
long long f[10000005], ans;
inline void getans(int n){
    f[1] = 1;
    int tmp, sum, d;
    for(int i = 2; i <= n; ++ i){
        if(!f[i]){
            for(int j = 2; j*i <= n; ++ j){
                tmp = j*i, sum = 0, d = i;
                while(tmp%i == 0) tmp /= i, sum += d, d *= i;
                if(!f[j*i]) f[j*i] = 1;
                f[j*i] *= sum;
            }
            f[i] = i+1;
        }
        if(i >= l) ans += abs(i+i-f[i]);
    }
}
int main(){
    scanf("%d%d",&l,&r);
    getans(r);
    printf("%I64d\n",ans);
    return 0;
}

Task 3:糖果

题目描述:

给出n(n<10^5)个节点,每个节点有一个权值p(p<10^7)。连接两个节点i,j的代价为min(pi%pj,pj%pi)。
求将这些节点连成一棵树的最小代价。

题目分析:

首先我们可以很显然的看出这道题就是一道最小生成树,但如果暴力建树的话,最多就会有n^2条边。
就算不考虑时间,但是空间上也过不了。
所以解题的关键就在于怎样把一些一定不会被用到的边删去,在连边的时候只连那些有可能被选中的边。
按照这样想下去。
如果我们先把点按从小到大排序。那么在i,j(i<j)之间连边的代价就一定是pj%pi。
那么我们可以这样考虑:将数轴pi等分。
那么在每个区间内对于i来说,如果连的边出现在最小生成树中的话,那么i只可能和这个区间内%pi最小的那个。
这样边就被优化成了n*log2(10^7)条,这样就可以过了。

Code:

#include <cstdio>
#include <cstring>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <vector>
#include<fstream>
#include<cstdlib>


using namespace std;

#define TRACE(x) cerr << #x << " = " << x << endl
#define REP(i, n) for (int i=0; i<n; i++)
#define FOR(i, a, b) for (int i=(a); i<(b); i++)

typedef long long ll;
typedef pair<int, int> P;
#define X first
#define Y second

const int MAXN = 1<<19, MAXM = 1e7 + 5;

vector <P> V[MAXM];
int najbliz[MAXM];
int p[MAXN];
int n;
int root[MAXN], rnk[MAXN];
int bio[MAXM], ozn[MAXM];

int find(int x)
{
  if (root[x] == -1) return x;
  return root[x] = find(root[x]);
}

void merge(int a, int b)
{
  a = find(a);
  b = find(b);
  assert(a != b);

  if (rnk[a] > rnk[b]) root[b] = a;
  else if (rnk[b] > rnk[a]) root[a] = b;
  else {
    rnk[a]++;
    root[b] = a;
  }
}

int main()
{
    freopen("sirni.in","r",stdin);
    freopen("sirni.out","w",stdout);
  scanf("%d", &n);
  memset(ozn, -1, sizeof ozn);
  REP(i, n) {
    scanf("%d", &p[i]);
    najbliz[p[i]] = p[i];
    if (ozn[p[i]] == -1)
      ozn[p[i]] = i;
  }

  for (int i=MAXM-2; i>=0; i--)
    if (!najbliz[i])
      najbliz[i] = najbliz[i+1];

  REP(i, n) {
    if (bio[p[i]]++) continue;
    if (najbliz[p[i]+1]) {
      if (2*p[i] >= MAXM || najbliz[2*p[i]] != najbliz[p[i]+1])
        V[najbliz[p[i]+1] - p[i]].push_back(P(i, ozn[najbliz[p[i]+1]]));
    }

    for (int j=2*p[i]; j<MAXM && najbliz[j]; j+=p[i])
      if (j + p[i] >= MAXM || najbliz[j+p[i]] != najbliz[j])
        V[najbliz[j]-j].push_back(P(i, ozn[najbliz[j]]));
  }

  memset(root, -1, sizeof root);
  ll rje = 0;
  REP(i, MAXM)
    REP(j, (int) V[i].size())
    if (find(V[i][j].X) != find(V[i][j].Y)) {
      merge(V[i][j].X, V[i][j].Y);
      rje += i;
    }

  REP(i, n) if (ozn[p[i]] == i) { assert(find(i) == find(0)); }

  printf("%lld\n", rje);

  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值