JOI 2017 Final题解

T1

把修改放到差分序列上做,这样每次修改只需要修改两个位置,且每次修改会对后面的所有温度产生影响

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define eps 1e-8
int n,m,a[200200];
ll f[200100];
ll s,t,ans;

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

void modify(int pos,ll val)
{
    if (pos>n) return;
    if (f[pos]>0) ans+=s*f[pos];
    else ans+=t*f[pos];
    f[pos]+=val;
    if (f[pos]>0) ans-=s*f[pos];
    else ans-=t*f[pos];
}

signed main()
{
    n=read();m=read();s=read();t=read();
    rep(i,0,n) a[i]=read();
    rep(i,1,n) f[i]=a[i]-a[i-1];
    ans=0;
    rep(i,1,n)
        if (f[i]>0) ans-=s*f[i];
        else ans-=t*f[i];
    while (m--)
    {
        int l=read(),r=read(),x=read();
        modify(l,x);modify(r+1,-x);
        printf("%lld\n",ans);
    }
    return 0;
}

T2

不难发现如果按照“快车->准快车->慢车”的顺序坐车一定不会更劣

对于每一段快车区间\((s_i,s_{i+1}]\),考虑如何求出最大的可到达车站

我们在\(s_i\)下车后会有一段剩余时间,记作\(rst_i\),和最开始的结论同理,我们希望在“最后一个可以使用慢车到达的车站”处建立一个准快车车站,使得从\(s_i\)可以直接到达那里,证明的话考虑往前或往后调整都不会是更优的

这样的话我们就有\(O(mk)\)个可以考虑的准快车建立点,使用优先队列贪心即可

注意一些奇奇怪怪的特判

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 998244353
#define int long long
#define eps 1e-8
int n,m,k,now[5050],s[5050];
ll a,b,c,tot,rst[5050];
priority_queue<int> q;
int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

signed main()
{
    n=read();m=read();k=read();
    scanf("%lld%lld%lld%lld",&a,&b,&c,&tot);
    rep(i,1,m) 
    {
        s[i]=read();
        rst[i]=tot-b*(s[i]-1);
        now[i]=s[i];
    }
    int ans=0;
    //rep(i,1,m) cout << now[i] << " ";cout << endl;
    if (b*(s[m]-1)>tot) ans--;
    rep(i,1,m-1)
    {
        if (rst[i]<0) continue;
        int nxt=min(s[i+1],s[i]+rst[i]/a+1);
        ans+=(nxt-s[i]);
        rst[i]-=c*(nxt-s[i]);
        now[i]=nxt;
    }
    rep(i,1,k)
    {
        rep(j,1,m-1)
        {
            if (rst[j]<0) continue;
            int nxt=min(s[j+1],now[j]+rst[j]/a+1);
            q.push(nxt-now[j]);
            rst[j]-=c*(nxt-now[j]);
            now[j]=nxt;
        }
    }
    rep(i,1,k-m)
    {
        if (q.empty()) break;
        ans+=q.top();q.pop();
    }
    printf("%lld",ans);
    return 0;
}

T3

画一下的话可以发现合法方案就是在四个角上的阶梯形,由于四种情况等价我们可以将矩阵旋转后只处理左下角的阶梯形,最后取个\(min\)即可

题目中由很明显的二分答案的暗示,但是看起来\(check\)不太容易

考虑矩阵的全局\(max\)\(min\)值,对于我们二分出来的\(mid\),我们考虑左下角的阶梯有\(\geq mid+min\),右上角的有\(\leq max-mid\),由于\(max\)\(min\)不会在同一个阶梯里,所以这样做我们一定能考虑到最优解,之后维护一个当前行的右端点指针(单调不降),每行判断一下在左下角不合法的点是否在右上角即可

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> pii;
const int N=10000;
const db pi=acos(-1.0);
#define lowbit(x) (x)&(-x)
#define sqr(x) (x)*(x)
#define rep(i,a,b) for (register int i=a;i<=b;i++)
#define per(i,a,b) for (register int i=a;i>=b;i--)
#define fir first
#define sec second
#define mp(a,b) make_pair(a,b)
#define pb(a) push_back(a)
#define maxd 2e9
#define eps 1e-8
int n,m,a[2020][2020],ans=maxd,mx=0,mn=maxd;

int read()
{
    int x=0,f=1;char ch=getchar();
    while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
    while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
    return x*f;
}

void reverse1()
{
    rep(i,1,n/2) rep(j,1,m) swap(a[i][j],a[n-i+1][j]);
}

void reverse2()
{
    rep(i,1,n) rep(j,1,m/2) swap(a[i][j],a[i][m-j+1]);
}

bool chk(int mid)
{
    int now=0;
    rep(i,1,n)
    {
        rep(j,1,m)
            if (a[i][j]<mx-mid) now=max(now,j);
        rep(j,1,m)
            if ((a[i][j]>mid+mn) && (j<=now)) return 0;
    }
    return 1;
}

void solve()
{
    int l=0,r=mx-mn,now=0;
    while (l<=r)
    {
        int mid=(l+r)>>1;
        if (chk(mid)) {now=mid;r=mid-1;}
        else l=mid+1;
    }
    ans=min(ans,now);
}

int main()
{
    n=read();m=read();
    rep(i,1,n) rep(j,1,m)
    {
        a[i][j]=read();
        mx=max(a[i][j],mx);
        mn=min(a[i][j],mn);
    }
    solve();
    reverse1();
    solve();
    reverse2();
    solve();
    reverse1();
    solve();
    printf("%d",ans);
    return 0;
}

T4

待填坑

猜你喜欢

转载自www.cnblogs.com/encodetalker/p/11817282.html