[20151018]SCZ训练

Sequence

【题目简述】
Fiugou 想要在一个长度为 N 的序列 A 中找到不同位置的三个数,以这三个数为三边长来构成一个三角形。但是它希望在满足条件下,这三个数的位置尽量靠前。具体地,设这三个数的为Ai,Aj,Ak, Fiugou 希望 k 尽量小;当 k 相等时,满足 j 尽量小;当k,j 均相等时,满足 尽量小。
但是这个序列中的数可能会发生变化。所以 Fiugou 给出了M个操作,形式如下:
1 x y:将 Ax 改为 y
2:查询最优的合法解,从小到大给出这三个数(而不是位置)。
【输入格式】
第一行一个整数 N,代表序列的长度。
第二行有 N 个整数,代表初始序列。
第三行一个整数 M,代表操作的个数。
接下来 M 行操作,两种操作格式如上所述。
【输出格式】
M行,每行三个数,从小到大给出。如果不存在,输出-1 -1 -1。
【样例输入】
6
7 1 3 4 5 1
3
2
1 3 5
2
【样例输出】
3 5 7
4 5 7
【数据范围】
对于10%的数据, N<=10,M<=5
对于30%的数据, N<=100,M<=25
对于50%的数据, N<=1000,M<=1000
对于100%的数据, N<=100000,M<=1000
对于100%的数据, 0<=Ai<=109,1<=x<=N,0<=y<=109

Solution :
注意到即使是 Fibnacci 数列在50项之后也超出 109 了,所以 503 枚举一下

Code :

/*************************************************************************
    > File Name: sequence.cpp
    > Author: Archer
 ************************************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;

const int N = 111111;
int n, seq[N], m;

typedef long long ll;
typedef pair<int, int> PII;
#define REP(i, l, r) for (int i = l; i <= r; i++)
#define MP make_pair

inline int read(){
    int x = 0, f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
inline void setIO(){
    freopen("sequence.in", "r", stdin);
    freopen("sequence.out", "w", stdout);
}
inline bool check(int x, int y, int z){
    return (seq[x] + seq[y] > seq[z] && seq[y] + seq[z] > seq[x] && seq[x] + seq[z] > seq[y]);
}
inline void solve(){
    REP(i, 3, min(n, 50)) REP(j, 2, i-1) REP(k, 1, j-1)
        if (check(i, j, k)){
            int _ = min(min(seq[i], seq[j]), seq[k]), __ = max(max(seq[i], seq[j]), seq[k]);
            printf("%d %d %d\n", _, seq[i] + seq[j] + seq[k] - _ - __, __);
            return;
        }
    printf("-1 -1 -1\n");
}
int main(){
    setIO();

    n = read();
    REP(i, 1, n) seq[i] = read();
    m = read();
    while (m--){
        int op = read();
        if (op == 2) solve();
        else{
            int x = read(), y = read();
            seq[x] = y;
        }
    }

    return 0;
}

登山

【题目简述】
,
,,,,,,
,NN,(0,0),(N,N)(x,y),(x+1,y),(x,y+1)(x,x),,(x,x+1)
,,,,,
,109+7
【输入格式】
N,C,NN,C
C,X,Y,X,YX>=Y,(X,Y)
C
【输出格式】
Ans,109+7
【数据范围】
对于 30%的数据, N<=5000
对于另外 20%的数据, C=0
对于另外 20%的数据, C=1
对于 100%的数据,保证 N<=100000,C<=1000
(0,0),(N,N)

Solution :
C比较小,这启示我们从障碍点入手。事实上也是这样的。我们将所有的障碍点以及 (N,N) 视为关键点,先将所有的关键点按x坐标从小到大排序,设 Fi 表示我们从 (0,0) 走到第i个关键点,除当前点以外不经过任何关键点的方案数。我们也要用补集的思想,也就是说先计算出会经过其他关键点的方案数,设 Gi 为这个方案数。假设一条这样的路径为 (P1,P2,...Pj,Pi) ,其中 Pj 是我们经过的第一个关键点。我们枚举这个 Pj ,那么 Gi=i1j=1FjWaysPj>Pi PjPi 。最后 Fi=Ways(0,0)>PiGi

Code :

/*************************************************************************
    > File Name: walk.cpp
    > Author: Archer
 ************************************************************************/
#include <bits/stdc++.h>
#define fe first
#define se second
using namespace std;
typedef pair<int,int> P;
const int MAXM = 1005,MAXN = 200015,Mo = int(1e9) + 7;
P Block[MAXM];
int Fc[MAXN],Rv[MAXN],F[MAXN],N,C;

int Quick(int a,int b){
    if (!b) return 1;
    int mid = Quick(a,b >> 1);
    if (b & 1) return mid * 1ll * mid % Mo * a % Mo;
    return mid * 1ll * mid % Mo;
}
int Getc(int n,int m){
    if (m > n) return 0;
    return Fc[n] * 1ll * Rv[m] % Mo * Rv[n - m] % Mo;
}
int Normal(int s,int t,int x,int y){
    if (x < s || y < t) return 0;
    return Getc(x + y - s - t,x - s);
}
int Walk(int s,int t,int x,int y){
    return (Normal(s,t,x,y) - Normal(s,t,y - 1,x + 1) + Mo) % Mo;
}
void setIO(){
    freopen("walk.in","r",stdin);
    freopen("walk.out","w",stdout);
}
int main(){
    setIO();
    scanf("%d%d", &N, &C);
    Fc[0] = 1;
    for(int i = 1;i <= N * 2 + 5;i ++) Fc[i] = Fc[i - 1] * 1ll * i % Mo;
    Rv[N * 2 + 5] = Quick(Fc[N * 2 + 5], Mo - 2);
    for(int i = N * 2 + 5;i;i --) Rv[i - 1] = Rv[i] * 1ll * i % Mo;
    for(int i = 1;i <= C;i ++) scanf("%d%d", &Block[i].fe, &Block[i].se);
    Block[++ C] = P(N,N);
    sort(Block + 1,Block + C + 1);
    for(int i = 1;i <= C;i ++)
    {
        F[i] = Walk(0,0,Block[i].fe,Block[i].se);
        for(int j = 1;j < i;j ++)
        if (Block[j].se <= Block[i].se)
            F[i] = (F[i] - F[j] * 1ll * Walk(Block[j].fe,Block[j].se,Block[i].fe,Block[i].se) % Mo + Mo) % Mo;
    }
    printf("%d\n", F[C]);
    return 0;
}

Melancholy

【题目简述】
DX3906,Melancholy,
N,(D,V):D,V
Q,D[L,R],KK,,KV
Q:P
,,V
Q232,,K,0
【输入格式】
,NQ
N,D
N,V
Q,3,L,R,K
【输出格式】
Q,,232
【数据范围】
1,2,3K=11<=N,Q<=105
4,5,61<=K<=21<=D,V<=109
7,81<=K<=31<=L<=R<=109
9,10 1<=K<=6
DV
【样例输入输出】
样例输入
53
54726
14532
671
262
183
样例输出
5
52
924
【样例解释】
V2,5,5
V1,2,3,4,2,3,4,2!(23+34+24)=52
V1,2,3,4,5,2,3,4,5,3!(234+235+245+345)=924

Solution :
线段树维护不去掉min的答案,然后容斥原理。

Code :

/*************************************************************************
    > File Name: melancholy.cpp
    > Author: Archer
 ************************************************************************/

#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;

typedef long long ll;
typedef unsigned int UI;
typedef pair<int, int> PII;
#define REP(i, l, r) for (int i = l; i <= r; i++)
#define MP make_pair
const int N = 111111;
int n, q;
struct node{int d, v; } blk[N];
struct Node{
    Node *lc, *rc; UI sum[10], mn; int l, r;
    void clear() { sum[0] = 1;}
    inline void merge(){
        REP(i, 1, 6) REP(j, 0, i) sum[i] += lc->sum[j] * rc->sum[i - j];
        mn = min(lc->mn, rc->mn);
    }
}pool[N << 4], *root, *tail = pool;
inline void setIO(){
    freopen("melancholy.in", "r", stdin);
    freopen("melancholy.out", "w", stdout);
}
inline int read(){
    int x = 0, f = 1; char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
    while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
inline void build(Node *(&rt), int l, int r){
    rt = tail++; rt->clear(); rt->l = l; rt->r = r;
    if (l == r){ rt->mn = rt->sum[1] = blk[l].v; return; }
    int mid = l+r >> 1;
    build(rt->lc, l, mid); build(rt->rc, mid + 1, r);
    rt->merge();
}
inline bool cmp(node x, node y) {return x.d < y.d; }
inline Node *merge(Node *t1, Node *t2){
    Node *ret = tail++; ret->lc = t1; ret->rc = t2;
    ret->merge(); ret->clear();
    return ret;
}
inline Node *query(Node *rt, int l, int r){
    if (l <= rt->l && rt->r <= r) { return rt; }
    int mid = rt->l+rt->r >> 1;
    if (r <= mid) return query(rt->lc, l, r);
    else if (l > mid) return query(rt->rc, l, r);
    else return merge(query(rt->lc, l, r), query(rt->rc, l, r));
}
inline int find(int x){
    int l = 0, r = n + 1;
    while (l + 1 < r){
        int mid = l+r >> 1;
        (blk[mid].d < x ? l : r) = mid;
    }
    return l;
}
int main(){
    setIO();

    n = read(); q = read();
    REP(i, 1, n) blk[i].d = read();
    REP(i, 1, n) blk[i].v = read(); 
    sort(blk + 1, blk + 1 + n, cmp);

    build(root, 1, n);

    while (q--){
        int L = read(), R = read(), k = read();
        int l = find(L) + 1, r = find(R + 1);
        if (l > r) {printf("0\n"); continue;}
        Node *info = query(root, l, r);
        info->clear(); 
        UI ans = info->sum[k], t = -info->mn;
        REP(i, 1, k) ans += t * info->sum[k - i], t *= -info->mn;
        REP(i, 1, k) ans *= i;
        printf("%u\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值