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]$
至于为什么,显然的改变的只有里面的,我们改变的只有
我考试时候想到了决策单调性但不知道在哪用(还是不熟...)
那么我们发现这个可以搞一个矩形最大值就好了(扫描线实现)...