分析

数据范围很小,可以考虑快排,再通过去重函数一下直接求解。时间复杂度为 。也可以开四个变量 扫一次得出答案。

代码

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 10010;
LL a[N],n,m;
int main() {
    scanf("%lld",&m);
    for(int i  =1;i <= m;i++ )scanf("%lld",&a[i]);
    sort(a+1,a+1+m);
    n = unique(a+1,a+1+m)-a-1;
    cout << a[n]-a[n-1]<<" "<<a[n]-a[2]<<" "<<a[n-1]-a[2]<<" "<<a[n-1]-a[1]<<endl;
    return 0;
}

分析

考虑一个节点的贡献是多少。那么它可以贡献的区域为 。把所有区间储存下来,把所有询问按右端点排序,这样前面的询问才不会影响后面的计算,树状数组维护一下就好了。复杂度为

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 100;
int read(){
    int x=0,f=0;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-')f=1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return f ? -x : x;
}
int a[N],t[N],last[N],m,n,ans;
struct Q{int l,r,id;}q[N];
bool cmp(Q x,Q y) {
    return x.r < y.r;
}
void add(int x,int d){
    for(int i = x;i <= n;i+=i&-i) t[i] += d;
}
int ask(int x){
    int tot = 0;
    for(int i = x;i;i -= i&-i) tot += t[i];
    return tot;
}
int main()
{
    n = read();
    for(int i = 1;i <= n;i++) a[i] = read();
    m = 0;
    for(int i = 1;i <= n;i++) {
        for(int j = 1;j <= n;j++) {
            q[++m].l = i;q[m].r = j;q[m].id = m; 
        }
    }
    sort(q+1,q+1+m,cmp);
    for(int i = 1,r = 0;i <= m;i++)
    {
        while(r < q[i].r)
        {
            r++;
            if(!last[a[r]]) last[a[r]] = r;
            else {
                add(last[a[r]],-1);
                last[a[r]] = r;
            } 
            add(r,1);
        }
        ans += ask(q[i].r) - ask(q[i].l-1);
    }
    cout << ans << endl;
    return 0;
} 

分析

一次,处理可以到达的所有节点。因为要最大值减去最小值最小,所以我们的答案一定是个连续的区间。考虑把可以到达的节点的值排个序,去重。记录一下最小的差就可以了。总的复杂度为

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1100;
#define LL long long
LL read() {
    LL x = 0,f = 0;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-')f=1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return f ? -x : x;
}
LL vis[N][N],pd[N][N],T,n,m,sx,sy,d,X;
LL st[N*N],top;
struct Node{LL x,y,d;};
queue<Node> q;
LL dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};
int main() {
    T = read();
    while(T--) {
        n = read();m = read();sx = read();
        sy = read();d = read();X = read();
        while(q.size()) q.pop();
        q.push((Node){sx,sy,d});
        memset(st,0,sizeof(st));top = 0;
        memset(vis,0,sizeof(vis));
        memset(pd,0,sizeof(pd));
        for(LL i = 1;i <= n;i++) {
            for(LL j = 1;j <= m;j++) pd[i][j] = read();
        }
        vis[sx][sy] = 1;
        while(q.size()) {
            Node a = q.front();q.pop();
            if(pd[a.x][a.y] == -1) continue;
            if(pd[a.x][a.y] > 0) st[++top] = pd[a.x][a.y];
            if(!a.d) continue;
            for(LL i = 0;i < 4;i++) {
                Node b;
                b.x = a.x + dx[i]; b.y = a.y + dy[i];
                b.d = a.d - 1;
                if(b.x<1||b.x>n||b.y<1||b.y>m||vis[b.x][b.y]||pd[b.x][b.y] == -1) continue;
                vis[b.x][b.y] = 1;q.push(b);
            }
        }
        sort(st+1,st+top+1);
        LL tot = unique(st+1,st+top+1)-st-1;
        LL ans = 0x3f3f3f3f3f3f3f3f;
        for(int i = 1;i <= tot;i++) {
            if(i + X - 1 > tot) continue;
            LL d = st[i+X-1]-st[i];
            ans = min(ans,d); 
        }
        if(ans == 0x3f3f3f3f3f3f3f3f) printf("no\n");
        else printf("%lld\n",ans);
    }
    return 0;
}

分析

考虑如果存在一个值 没有取,而且这是个合法方案,那么所有比 大的值是可以不取的,这就是个类似 背包的技术问题了,为了不重不漏的考虑所有方案,我们钦定一个值 没有取,且 的值全部取了。那么排序,计算前缀和,最后对于后面 的值进行 转移就好了。时间复杂度为 。但是 这就很迷惑了,要么是我时间复杂度算错了,要不就是数据太水,导致这个思路的代码可以通过。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 31000;
#define LL long long
LL read() {
    LL x=0,f=0;char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-')f=1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    return f ? -x : x;
}

LL n,T,a[N],f[N],s[N];
//bool cmp(int x,int y) {return x > y;}
LL ans = 0;
int main() {
//    memset(f,-1,sizeof(f));
    n = read();T = read();
    for(int i = 1;i <= n;i++) a[i] = read();
    sort(a+1,a+1+n);
    for(LL i = 1;i <= n;i++) s[i] = s[i-1] + a[i];
    for(LL i = 1;i <= n;i++) // 下一个法术
    {
        LL sum = s[i-1];
        if(T-sum < 0) continue;
        memset(f,0,sizeof(f));
        f[0] = 1;T -= sum;
        for(int j = i+1;j <= n;j++) {
            for(int t = T;t >= a[j];t--){
                f[t] = f[t] + f[t-a[j]];
            }
        } 
        for(LL j = max(T - a[i] + 1,0LL);j <= T;j++) ans += f[j];
        T += sum;
    } 
    cout << ans << endl;
    return 0;
}