10月22日比赛

T1

就是有 \(n\) 个人,每个人有一个工作时间和休息时间,这些时间都是连续的,一个人工作时,其他人工作过的可以休息,休息到了时间就可继续工作

求至少多少人在一起是可以连续工作。

题解

考虑 \(a_i + b_i\) 在不断枚举的过程中,我们需要不断维护答案.

那么新加入一个的时候,我们直接把他加入\(set\),然后判断删掉最小值之后是否剩下\(a_i\) 的和还满足条件.

对于某次set里的值不满足条件时,那么这次的答案就应该比上一个答案要大,所以直接无视就行.

时间复杂度 \(O(NlogN)\)

int cmp(Node a,Node b){return a.y<b.y;}
int main() {
	scanf("%d",&n);
	for (int i=1;i<=n;++i) a[i].x=read(),a[i].y=read(),a[i].y+=a[i].x;
	sort(a+1,a+n+1,cmp); 
	for (int i=1;i<=n;++i) {
			st.insert(a[i].x); ans+=a[i].x;
			while (st.size()>1&&ans-(*st.begin())>=a[i].y) 
                ans-=*st.begin(),st.erase(st.begin());
			if (ans>=a[i].y) Ans=min(Ans,(int)st.size());
	}
	if (Ans>n) puts("-1");
	else printf("%d\n",Ans);
}

T2

求两个序列的最长公共波浪子序列。
当一个序列没有连续三个元素,满足它们都是不增的或不降的就是一个波浪序列。

题解

直接跑最长上升子序列,然后转移过程看合不合法,复杂度 \(O(n^2m^2)\),70pts

\(f_{i,j,0/1}, g_{i,j,0/1}\)分别表示第一阶段,第二阶段.

i,j,k − > fi+1,j,k .
\(a_i\)\(b_j\) 满足关系 \(k\),则 \(g_{i,j+1,k} <− f_{i,j,k}\).
\(g_{i,j,k} −> g_{i,j+1,k}\)
\(a_i == b_j\) ,则 \(f_{i+1,j,k} xor 1 <− g_{i,j,k + 1}\).
时间复杂度 \(O(NM)\) 100pts

#include<bits/stdc++.h>
using namespace std;
int read() {
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c=='-')f=-1;c = getchar();}
    while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48);c = getchar();}
    return x*f;
}
int a[10001],b[10001],n,m;
struct op{
    int val,dcd,ucd,lt;
}f[5007][5007];
op Max(op x,op y) {
    if(x.val>y.val) return x;
    else return y;
}
int main() {
    n=read();
    for(int i = 1;i <= n;++ i) a[i] = read();
    m=read();
    for(int j = 1;j <= m;++ j) b[j] = read();
    for(int i = 1;i <= n;++ i) {
        for(int j = 1;j <= m;++ j) {
            f[i][j].lt=-2e9;
            f[i][j].ucd=1;
            f[i][j].dcd=1; 
        }
    } 
    for(int i = 1;i <= n;++ i) {
        for(int j = 1;j <= m;++ j) {
            if((a[i]==b[j])) {
                if(f[i][j].val<f[i-1][j-1].val+1) {
                    if(f[i-1][j-1].lt!=-2e9) {
                        if(f[i-1][j-1].lt<=a[i]) f[i][j].dcd=f[i-1][j-1].dcd+1;
                        if(f[i-1][j-1].lt>=a[i]) f[i][j].ucd=f[i-1][j-1].ucd+1;
                        if(f[i][j].ucd>=3||f[i][j].dcd>=3) {
                            f[i][j].val = f[i-1][j-1].val;
                            f[i][j].ucd=f[i-1][j-1].ucd; f[i][j].dcd=f[i-1][j-1].dcd;
                            f[i][j].lt = f[i-1][j-1].lt;
                        }
                        else {
                            f[i][j].val = f[i-1][j-1].val+1;
                            f[i][j].lt = a[i];
                        }
                    }
                    else {
                        f[i][j].val = f[i-1][j-1].val+1;
                        f[i][j].lt = a[i];
                    }
                }
                else if(f[i][j].val==f[i-1][j-1].val+1) {
                    f[i][j] = f[i-1][j-1];
                }
            }
            f[i][j] = Max(f[i][j],Max(f[i][j-1],f[i-1][j]));
        }
    }
    cout<<f[n][m].val+2;
	return 0;
}

T3

\(n\) 个点和两人,这两人其中一个不动另一个去找他,对于第 \(i\) 个点,可以传送到 \((max(1,i-a_i),min(i,i+a_i))\)中的任意一个点,花费1。
他们想相遇且花费最少,求最坏情况下的花费。

题解

连边直接跑最短路即可,60pts

然后线段树优化建边,再跑最短路即可100pts。

#include<bits/stdc++.h>
using namespace std;
int read() {
    int x = 0,f = 1; char c = getchar();
    while(c < '0'||c > '9') {if(c=='-')f=-1;c = getchar();}
    while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48);c = getchar();}
    return x*f;
}
struct op{
    int to,nxt;
}e[1000001];
int head[1000001],num;
void add(int frm,int to) {
    e[++num] = op{to,head[frm]};
    head[frm] = num;
}
int n,a,ans;
struct opp{
    int diss;
    int wz;
    bool operator <(const opp&jk) const {
        return jk.diss<diss;
    }
};
int ds[1001][1001];
bool vis[1000001]; 
priority_queue<opp>q;
void dij(int s,int cs) {
    for(int i = 1;i <= n;++ i) ds[cs][i] = 1e9,vis[i] = 0;
    q.push(opp{0,s}); ds[cs][s] = 0;
    while(!q.empty()) {
        int x = q.top().wz; q.pop();
        if(vis[x]) continue; vis[x] = 1;
        for(int i = head[x];i;i = e[i].nxt) {
            int v = e[i].to;
            if(ds[cs][v] > ds[cs][x]+1) {
                ds[cs][v] = ds[cs][x]+1;
                q.push(opp{ds[cs][v],v});
            }
        }
    }
}
int main() {
    cin>>n;
    for(int i = 1;i <= n;++ i) {
        a = read();
        for(int j = max(1,i-a);j <= min(n,i+a);++ j) {
            if(i==j) continue;
            add(i,j);
        }
    }
    for(int i = 1;i <= n;++ i) dij(i,i);
    for(int i = 1;i <= n;++ i) {
        for(int j = 1;j <= n;++ j) {
            if(i!=j) {
                ans = max(ans,min(ds[i][j],ds[j][i]));
            }
        }
    }
    cout<<ans;
	return 0;
}
posted @ 2022-10-23 09:21  双枫  阅读(31)  评论(0)    收藏  举报