如果这次操作的前一次是自己的操作,因为l是从

作者: 编程  发布:2019-09-26

所有操作可以分解为由两步组成的操作:第一步是在数列的某一端取一个数并加到自己的得分上,第二步是把下一步操作的权利给自己或对方。如果这次操作的前一次是对方的操作,那么在左端或右端取数没有限制;如果这次操作的前一次是自己的操作,那么必须与上一次在相同的一端操作。

9159.com ,洛谷 P1430 序列取数,p1430

如果按照

所有操作可以分解为由两步组成的操作:第一步是在数列的某一端取一个数并加到自己的得分上,第二步是把下一步操作的权利给自己或对方。如果这次操作的前一次是对方的操作,那么在左端或右端取数没有限制;如果这次操作的前一次是自己的操作,那么必须与上一次在相同的一端操作。

令ans[l][r][0/1/2]表示l到r的子序列,上一次操作是(0->对方取)或(1->自己取左端)或(2->自己取右端),先取者的最高得分。则可以得到状态转移方程。复杂度$O(n^2)$。

(枚举状态要按照一定的顺序)

这题卡常!

 1 #pragma GCC diagnostic error "-std=c++11"
 2 #pragma GCC target("avx")
 3 #pragma GCC optimize(3)
 4 #pragma GCC optimize("Ofast")
 5 #pragma GCC optimize("inline")
 6 #pragma GCC optimize("-fgcse")
 7 #pragma GCC optimize("-fgcse-lm")
 8 #pragma GCC optimize("-fipa-sra")
 9 #pragma GCC optimize("-ftree-pre")
10 #pragma GCC optimize("-ftree-vrp")
11 #pragma GCC optimize("-fpeephole2")
12 #pragma GCC optimize("-ffast-math")
13 #pragma GCC optimize("-fsched-spec")
14 #pragma GCC optimize("unroll-loops")
15 #pragma GCC optimize("-falign-jumps")
16 #pragma GCC optimize("-falign-loops")
17 #pragma GCC optimize("-falign-labels")
18 #pragma GCC optimize("-fdevirtualize")
19 #pragma GCC optimize("-fcaller-saves")
20 #pragma GCC optimize("-fcrossjumping")
21 #pragma GCC optimize("-fthread-jumps")
22 #pragma GCC optimize("-funroll-loops")
23 #pragma GCC optimize("-fwhole-program")
24 #pragma GCC optimize("-freorder-blocks")
25 #pragma GCC optimize("-fschedule-insns")
26 #pragma GCC optimize("inline-functions")
27 #pragma GCC optimize("-ftree-tail-merge")
28 #pragma GCC optimize("-fschedule-insns2")
29 #pragma GCC optimize("-fstrict-aliasing")
30 #pragma GCC optimize("-fstrict-overflow")
31 #pragma GCC optimize("-falign-functions")
32 #pragma GCC optimize("-fcse-skip-blocks")
33 #pragma GCC optimize("-fcse-follow-jumps")
34 #pragma GCC optimize("-fsched-interblock")
35 #pragma GCC optimize("-fpartial-inlining")
36 #pragma GCC optimize("no-stack-protector")
37 #pragma GCC optimize("-freorder-functions")
38 #pragma GCC optimize("-findirect-inlining")
39 #pragma GCC optimize("-fhoist-adjacent-loads")
40 #pragma GCC optimize("-frerun-cse-after-loop")
41 #pragma GCC optimize("inline-small-functions")
42 #pragma GCC optimize("-finline-small-functions")
43 #pragma GCC optimize("-ftree-switch-conversion")
44 #pragma GCC optimize("-foptimize-sibling-calls")
45 #pragma GCC optimize("-fexpensive-optimizations")
46 #pragma GCC optimize("-funsafe-loop-optimizations")
47 #pragma GCC optimize("inline-functions-called-once")
48 #pragma GCC optimize("-fdelete-null-pointer-checks")
49 #include<cstdio>
50 #include<cstring>
51 #include<algorithm>
52 using namespace std;
53 int sum[1010],ans[1010][1010][3],a[1010],T,n;
54 inline int read() {
55     int x=0,f=1;char ch=getchar();
56     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
57     while(ch>='0'&&ch<='9'){x*=10;x+=(ch-'0');ch=getchar();}
58     return x*f;
59 }
60 inline void write(int x) {
61     if(x<0) putchar('-'),x=-x;
62     if(x>9) write(x/10);
63     putchar(x%10+'0');
64 }
65 int main()
66 {
67     register int i,l;
68     int r;
69     T=read();
70     while(T--)
71     {
72         memset(ans,0,sizeof(ans));
73         n=read();
74         for(i=1;i<=n;++i)
75             a[i]=read();
76         for(i=1;i<=n;++i)
77             sum[i]=sum[i-1]+a[i];
78         for(i=1;i<=n;++i)
79             ans[i][i][0]=ans[i][i][1]=ans[i][i][2]=a[i];
80         for(i=2;i<=n;++i)
81             for(l=1;l<=n-i+1;++l)
82             {
83                 r=l+i-1;
84                 ans[l][r][0]=max(sum[r]-sum[l-1]-min(ans[l+1][r][0],ans[l][r-1][0]),max(a[l]+ans[l+1][r][1],a[r]+ans[l][r-1][2]));
85                 ans[l][r][1]=max(sum[r]-sum[l-1]-ans[l+1][r][0],a[l]+ans[l+1][r][1]);
86                 ans[l][r][2]=max(sum[r]-sum[l-1]-ans[l][r-1][0],a[r]+ans[l][r-1][2]);
87             }
88         write(ans[1][n][0]);putchar('n');
89     }
90     return 0;
91 }

P1430 序列取数,p1430 如果按照...

Input示例

7
6 6 2 7 4 2 5
7
1 3 6
2 2 4 2
2 2 4 7
2 2 2 5
1 2 6
1 1 4
2 1 7 3
#include "iostream"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#define ll long long
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a) memset(a,0,sizeof(a))
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
using namespace std;
const long long INF = 1e18+1LL;
const int inf = 1e9+1e8;
const int N=1e5+100;
const ll mod=1e9+7;

struct Node{
    int l, r;
    bool friend operator< ( Node a, Node b){
        if(a.l==b.l) return a.r<b.r;
        return a.l<b.l;
    }
};
Node arr[105];
int n,ans=-1;
int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1; i<=n; ++i){
        int x,y;
        cin>>x>>y;
        arr[i].l=min(x,y);
        arr[i].r=max(x,y);
    }
    sort(arr+1,arr+1+n);
    int p=inf;
    for(int i=1; i<=n; ++i){
        if(arr[i].r>=p){
            if(arr[i].l<p){
                ans++;
            }
            else p=arr[i].r;
        }
        else{
            ans++;
            p=arr[i].r;
        }
    }
    cout<<n-ans<<"n";
    return 0;
}

这题卡常!

题解

这道题可以用分块做!(其实我就是想练习分块才来写的这道题……)

大约(sqrt n)(因为担心空间爆炸,我取的是400个一块)分成一块,每块内部是一个链表。对于每一块,记录某数在其中出现的次数。

当进行修改的时候,把右端点上的元素拿下来,插到左端点前面即可。但是单纯这样做,可能会导致有的块变大、有的块变小,不利于时间复杂度的稳定,于是把区间中间的每一块最右边的元素拿下来,插到下一个块的左端点前面,这样每次修改时块的大小不会改变。

注意可能出现修改区间的 l, r 相等的情况——对于我的代码,这里不特判的话链表操作就会GG……

#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define space putchar(' ')
#define enter putchar('n')
using namespace std;
typedef long long ll;
template <class T>
bool read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
        else if(c == EOF) return 0;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
    return 1;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int M = 400, N = 1e5+400;
int n, q, a[N];
int st[N/M], ed[N/M], pre[N], nxt[N];
int blk[N], beg[N];
// 使用链表存储每一块内部信息
// blk是原来某一编号的元素的所在的位置
int cnt[N/M][N], ans; // 记录每一块内每个数有多少

void erase(int x){ //删除元素x
    pre[nxt[x]] = pre[x];
    nxt[pre[x]] = nxt[x];
    cnt[blk[x]][a[x]]--;
}
void insert(int x, int y){ //在x前面插入y(同一块)
    pre[y] = pre[x];
    nxt[y] = x;
    nxt[pre[x]] = y;
    pre[x] = y;
    blk[y] = blk[x];
    cnt[blk[y]][a[y]]++;
}
int find(int x){ //找到第x个元素
    int b = 1;
    while(b < blk[n] && beg[b + 1] <= x) b++;
    int ret = nxt[st[b]], pos = beg[b];
    while(pos < x) pos++, ret = nxt[ret];
    return ret;
}
void change(int l, int r){
    int left = find(l), right = find(r);
    int b1 = blk[left], b2 = blk[right];
    erase(right);
    insert(left, right);
    for(int b = b1; b < b2; b++){
        int x = pre[ed[b]];
        erase(x);
        insert(nxt[st[b + 1]], x);
    }
}
int query(int l, int r, int x){
    int left = find(l), right = find(r);
    int b1 = blk[left], b2 = blk[right];
    int ret = 0;
    if(b1 == b2){
        for(int i = left; i != nxt[right]; i = nxt[i])
            if(a[i] == x) ret++;
        return ret;
    }
    for(int pos = beg[b1 + 1] - 1, i = pre[ed[b1]]; pos >= l; pos--, i = pre[i])
        if(a[i] == x) ret++;
    for(int pos = beg[b2], i = nxt[st[b2]]; pos <= r; pos++, i = nxt[i])
        if(a[i] == x) ret++;
    for(int b = b1 + 1; b < b2; b++)
        ret += cnt[b][x];
    return ret;
}
int main(){
    read(n);
    for(int i = 1; i <= n; i++){
        read(a[i]);
        pre[i] = i - 1, nxt[i] = i + 1, blk[i] = (i - 1) / M + 1;
        if(i % M == 1)
            beg[blk[i]] = i, st[blk[i]] = n + blk[i], pre[i] = st[blk[i]], nxt[st[blk[i]]] = i;
        if(i % M == 0 || i == n)
            ed[blk[i]] = n + blk[i], nxt[i] = ed[blk[i]], pre[ed[blk[i]]] = i;
        cnt[blk[i]][a[i]]++;
    }
    beg[blk[n] + 1] = n + 1;
    read(q);
    while(q--){
        int op, l, r, x;
        read(op), read(l), read(r);
        l = (l + ans - 1) % n + 1;
        r = (r + ans - 1) % n + 1;
        if(l > r) swap(l, r);
        if(op == 1 && l != r)
            change(l, r);
        else if(op == 2){
            read(x);
            x = (x + ans - 1) % n + 1;
            write(ans = query(l, r, x)), enter;
        }
    }
    return 0;
}

AC代码:

令ans[l][r][0/1/2]表示l到r的子序列,上一次操作是(0->对方取)或(1->自己取左端)或(2->自己取右端),先取者的最高得分。则可以得到状态转移方程。复杂度$O$。

Output

对于每一个第二种类型的问题以单独一行输出答案。

 

 1 #pragma GCC diagnostic error "-std=c++11" 2 #pragma GCC target 3 #pragma GCC optimize 4 #pragma GCC optimize 5 #pragma GCC optimize 6 #pragma GCC optimize 7 #pragma GCC optimize("-fgcse-lm") 8 #pragma GCC optimize("-fipa-sra") 9 #pragma GCC optimize("-ftree-pre")10 #pragma GCC optimize("-ftree-vrp")11 #pragma GCC optimize("-fpeephole2")12 #pragma GCC optimize("-ffast-math")13 #pragma GCC optimize("-fsched-spec")14 #pragma GCC optimize("unroll-loops")15 #pragma GCC optimize("-falign-jumps")16 #pragma GCC optimize("-falign-loops")17 #pragma GCC optimize("-falign-labels")18 #pragma GCC optimize("-fdevirtualize")19 #pragma GCC optimize("-fcaller-saves")20 #pragma GCC optimize("-fcrossjumping")21 #pragma GCC optimize("-fthread-jumps")22 #pragma GCC optimize("-funroll-loops")23 #pragma GCC optimize("-fwhole-program")24 #pragma GCC optimize("-freorder-blocks")25 #pragma GCC optimize("-fschedule-insns")26 #pragma GCC optimize("inline-functions")27 #pragma GCC optimize("-ftree-tail-merge")28 #pragma GCC optimize("-fschedule-insns2")29 #pragma GCC optimize("-fstrict-aliasing")30 #pragma GCC optimize("-fstrict-overflow")31 #pragma GCC optimize("-falign-functions")32 #pragma GCC optimize("-fcse-skip-blocks")33 #pragma GCC optimize("-fcse-follow-jumps")34 #pragma GCC optimize("-fsched-interblock")35 #pragma GCC optimize("-fpartial-inlining")36 #pragma GCC optimize("no-stack-protector")37 #pragma GCC optimize("-freorder-functions")38 #pragma GCC optimize("-findirect-inlining")39 #pragma GCC optimize("-fhoist-adjacent-loads")40 #pragma GCC optimize("-frerun-cse-after-loop")41 #pragma GCC optimize("inline-small-functions")42 #pragma GCC optimize("-finline-small-functions")43 #pragma GCC optimize("-ftree-switch-conversion")44 #pragma GCC optimize("-foptimize-sibling-calls")45 #pragma GCC optimize("-fexpensive-optimizations")46 #pragma GCC optimize("-funsafe-loop-optimizations")47 #pragma GCC optimize("inline-functions-called-once")48 #pragma GCC optimize("-fdelete-null-pointer-checks")49 #include<cstdio>50 #include<cstring>51 #include<algorithm>52 using namespace std;53 int sum[1010],ans[1010][1010][3],a[1010],T,n;54 inline int read() {55     int x=0,f=1;char ch=getchar();56     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}57     while(ch>='0'&&ch<='9'){x*=10;x+=(ch-'0');ch=getchar();}58     return x*f;59 }60 inline void write(int x) {61     if(x<0) putchar('-'),x=-x;62     if(x>9) write(x/10);63     putchar(x%10+'0');64 }65 int main()66 {67     register int i,l;68     int r;69     T=read();70     while(T--)71     {72         memset(ans,0,sizeof;73         n=read();74         for(i=1;i<=n;++i)75             a[i]=read();76         for(i=1;i<=n;++i)77             sum[i]=sum[i-1]+a[i];78         for(i=1;i<=n;++i)79             ans[i][i][0]=ans[i][i][1]=ans[i][i][2]=a[i];80         for(i=2;i<=n;++i)81             for(l=1;l<=n-i+1;++l)82             {83                 r=l+i-1;84                 ans[l][r][0]=max(sum[r]-sum[l-1]-min(ans[l+1][r][0],ans[l][r-1][0]),max(a[l]+ans[l+1][r][1],a[r]+ans[l][r-1][2]));85                 ans[l][r][1]=max(sum[r]-sum[l-1]-ans[l+1][r][0],a[l]+ans[l+1][r][1]);86                 ans[l][r][2]=max(sum[r]-sum[l-1]-ans[l][r-1][0],a[r]+ans[l][r-1][2]);87             }88         write(ans[1][n][0]);putchar('n');89     }90     return 0;91 }

Output示例

2
1
0
0

1214 线段覆盖

如果按照

51nod 1471 小S的兴趣

思路:贪心,先按l排序后按r排序,每次标记当前剩下线段的最右端,因为l是从小到达有序的,所以不需要考虑左端点,只需要考虑右边尽量往左端点取就是了

(枚举状态要按照一定的顺序)

Input

第一行包含整数 n (1 ≤ n ≤ 10*5) —数组元素的数量。第二行包含 n 个整数a[1], a[2], ..., a[n] (1 ≤ a[i] ≤ n)。

第三行包含唯一的整数 q (1 ≤ q ≤ 10*5) —问题的数量。接下来的q行包含了这些询问。

因为你需要在线回答这些问题,所以这些问题将会被编码。第一种类型的询问将会以以下形式给出: 1 Li Ri 。第二种类型的询问将会以以下形式给出: 2 Li Ri Ki 。所有输入的数字都是整数,它们满足以下条件:1 ≤ Li,Ri,Ki ≤ n.

为解码输入的问题,你需要按以下转换操作:
li = ((Li + lastans - 1) mod n) + 1;
ri = ((Ri + lastans - 1) mod n) + 1;
ki=((Ki + lastans - 1) mod n) + 1.
lastans 是到当前询问为止最后一个第二种类型的询问的答案 (初始, lastans = 0)。如果转换后, li 比 ri 大,你需要交换这两个数字。

题意:中文题

题面

小S喜欢有趣的事。但是,每个人的兴趣都是独特的。小S热衷于自问自答。有一天,小S想出了一个问题。
有一个包含n个正整数的数组a和针对这个数组的几个问题。这些问题有两种类型:

  1. 在数组下标l到r的部分上,将一个单元格循环移动到右端。即以下面方式重新分配数组上的元素。

    a[l], a[l+1], ..., a[r-1], a[r] → a[r], a[l], a[l+1], ..., a[r-1].

  2. 在数组下标l到r的部分上,计算有多少元素的值与k相等。

小S很喜欢这个问题并且很快解决了它,你是否能够解决它呢?

本文由9159.com发布于编程,转载请注明出处:如果这次操作的前一次是自己的操作,因为l是从

关键词:

上一篇:没有了
下一篇:没有了