3.4省选模拟

$3.4$

$T1$

神奇贪心,不过暴力$dp$可以拿$60pts$

考场代码,由于读入出错,最大值设小了$60->3$...

改后暴力代码

#include<bits/stdc++.h>
#define INF 1e60
#define int __int128_t
#define MAXN 100005
#define MAXM 5005
using namespace std;
bool poz[MAXN][7];
int n,m,A,B,Ans=INF;
int dp[2][MAXM],tr[MAXN];
char ch[100];
int lowbit(int x){return x&(-x);}
void Insert(int poz,int k){while(poz<=n) tr[poz]+=k,poz+=lowbit(poz);}
int query(int poz){int res=0;while(poz)res+=tr[poz],poz-=lowbit(poz);return res;}
inline int rd(){
    int r = 0 , w = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0') {if(ch == '-') w = -1; ch = getchar();} 
    while(ch >='0' && ch <='9') {r = r * 10 + ch -'0'; ch = getchar();}
    return r * w;
}
void print(int x)
{
     long long cnt=0,Mid[1000];
     while(x)
     {
            Mid[++cnt]=x%10;
            x/=10;
     }
     for(int i=cnt;i>=1;i--)
     {
          cout<<Mid[i];
     }
}
signed main()
{
//    freopen("a.in","r",stdin);
//    freopen("a.out","w",stdout);
    n=rd();
    m=rd();
    A=rd();
    B=rd();
    //scanf("%lld%lld%lld%lld",&n,&m,&A,&B);
    for(int i=1;i<=n;i++) Insert(i,2);
    memset(poz,true,sizeof(poz));
    int now,pre,res1,res2;
    long long lie,wei;
    for(int i=1;i<=m;i++)
    {
        now=i%2;
        pre=now^1;
        memset(dp[now],0x7f,sizeof(dp[now]));
        scanf("%s",ch);
        int Now=0;
        lie=0,wei=0;
        while(ch[Now]>='0'&&ch[Now]<='9')
        {
              lie=lie*10+ch[Now]-'0';
              Now++;
        }
        wei=ch[Now]-'A'+1;
        for(int j=0;j<=i;j++)
        {
            res1=res2=0;
            res1=(j-1)*B+query(lie-1)*A;
            res2=(i-1-j)*B+(query(n)-query(lie))*A;
            if(j==i) res2=1e20;
            if(j==0) res1=1e20;
            if(wei<=3)
            {
               for(int k=wei+1;k<=4;k++)
               {
                      res1+=(poz[lie][k]==true?1:0)*A;
                      res2+=(poz[lie][k]==true?1:0)*A;
               }
            }
            else
            {
               for(int k=wei-1;k>=3;k--)
               {
                      res1+=(poz[lie][k]==true?1:0)*A;
                      res2+=(poz[lie][k]==true?1:0)*A;
               }
            }
            dp[now][j]=min(dp[pre][j-1]+res1,dp[pre][j]+res2);
        }
        poz[lie][wei]=false;
        if(wei==3||wei==4) Insert(lie,-1);
        
    }
    for(int i=0;i<=m;i++) Ans=min(Ans,dp[m%2][i]);
    print(Ans);
    //cout<<Ans<<endl;
}
/*
5 5 3 4
3E
1D
5C
1E
4A
*/

 

正解

首先可以确定的是,经过的点是不变的,那么变化量只有选择哪个而已

那么就把两种情况的都放进一个$pair$

然后根据两种情况差值从大到小排个序,然后把$first/second$分别前/后缀和一下

然后枚举峰值在哪里取到,前面的都选前面,后面的都选后面的都选后面就好了

至于为什么...

最终的贡献显然可以分成两部分,经过的贡献是固定的,只需要判断每个选那个就好了

然后剩余的就是两个里面的各选了多少个了

那么证明的话,考虑先全选一个,然后换一个差值最大的搞进去就好了

$T2$

显然可以$n^2$枚举,压力来到如何判断大小方面,只需要写一个$bitset$模拟二进制加减法就好了

具体:

首先把每个点向周围八个方向最近点连边,然后跑最短路就好了,显然这个不太能$dp$,因为有后效性

但是这个东西显然是一个最短路...那么每个点又只能往最近的点走,显然其余的点不会更优

考虑一个方向,即使不走最近的,也能从最近的转移过来

$T3$

显然的,交换前面小的和后面大的是不明智的...

考虑交换两个数字$i<j,h_i>h_j$的贡献是多少

贡献$1+2\sum_{k=i}^j[h_j<h_k<h_i]$

至于为什么,显然的改变的只有里面的,我们改变的只有

我考试时候想到了决策单调性但不知道在哪用(还是不熟...)

那么我们发现这个可以搞一个矩形最大值就好了(扫描线实现)...

posted @ 2022-03-04 14:57  Authentic_k  阅读(48)  评论(0编辑  收藏  举报