【题解】洛谷P3531、P1966:LIT-Letters 、火柴排队
P3531 [POI2012] LIT-Letters
写了个假做法有点伤心,本以为是两个都求逆序对然后答案相减,但是这样在部分数据上确实合法,但是实际上毫无章法没有逻辑。
正解考虑贪心,我们一个数字肯定要找最前面,第二次出现就去最前面第二次出现的位置,因为如果第一个A放在了后面,那么就有可能产生更对逆序对(因为你把大的数放在了前面)。
我们对每个字母重新编号,\(A\) 为 ABC
编号为 123
,\(B\) 为 CBA
编号为 321
。
接下来就可以正常求逆序对了。
其实思想就是多个重复的我们进行去重,让他们有对应的编号,像原来为 \(A\) 为 010
,\(B\) 为 100
,完全没法去逆序对,不知道的还以为是区间差逆序对呢,但是我们重编号就为 123,213
这就很明确了,我们都尽量向前靠,每个数该去哪就去哪。
#include<bits/stdc++.h> #define int long long #define ls p<<1 #define rs p<<1|1 #define re register const int N=1e6+10; const int mod=998244353; using namespace std; int n; int a[N],b[N]; int t[N]; int lb(int x){ return x&-x; } void add(int x,int k){ while(x<=n){ t[x]+=k; x+=lb(x); } } int query(int x){ int sum=0; while(x){ sum+=t[x]; x-=lb(x); } return sum; } int vis[30][N]; int tt[100]; signed main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n; for(int i=1;i<=n;i++){ char c; cin>>c; a[i]=c-'A'+2; } for(int i=1;i<=n;i++){ char c; cin>>c; b[i]=c-'A'+2; } for(int i=1;i<=n;i++){ vis[a[i]][++vis[a[i]][0]]=i; } for(int i=1;i<=n;i++){ b[i]=vis[b[i]][++tt[b[i]]]; } int ans=0; for(int i=n;i>=1;i--){ ans+=query(b[i]-1); add(b[i],1); } cout<<ans; return 0; }
P1966 [NOIP2013 提高组] 火柴排队
这是上面那题的略微复杂版,可以想到上面最大与下面最大这样造成的代价最小,欸!是大小关系不是具体数值,我们进行离散化去重可以分别得到 1 3 4 2 与 1 4 2 3
,可以发现到这就是对应数字到对应位置,直接套上一题的模板即可,注意:题目已经说了一盒火柴互不相同所以不用去重,但就这样吧。
#include<bits/stdc++.h> //#define int long long #define ll long long #define ls p<<1 #define rs p<<1|1 #define re register const int N=1e5+10; const int mod=1e8-3; using namespace std; int n; int a[N],b[N]; ll t[N]; inline int lb(int x){ return x&-x; } int mx=0; inline void add(int x,int k){ while(x<=mx){ t[x]+=k; t[x]%=mod; x+=lb(x); } } inline int query(int x){ ll sum=0; while(x){ sum+=t[x]; sum%=mod; x-=lb(x); } return sum; } int vis[N][100]; int tt[N]; int f1[N],o1=0; int f2[N],o2=0; signed main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n; for(re int i=1;i<=n;i++){ cin>>a[i]; f1[++o1]=a[i]; } for(re int i=1;i<=n;i++){ cin>>b[i]; f2[++o2]=b[i]; } sort(f1+1,f1+o1+1); sort(f2+1,f2+o2+1); int tot1=unique(f1+1,f1+o1+1)-f1-1; int tot2=unique(f2+1,f2+o2+1)-f2-1; for(re int i=1;i<=n;i++){ a[i]=lower_bound(f1+1,f1+1+tot1,a[i])-f1; b[i]=lower_bound(f2+1,f2+1+tot2,b[i])-f2; } if(tot1<tot2){ swap(a,b); } mx=max(tot1,tot2); // cout<<tot1<<" "<<tot2; for(re int i=1;i<=n;i++){ vis[a[i]][++vis[a[i]][0]]=i; } for(re int i=1;i<=n;i++){ b[i]=vis[b[i]][++tt[b[i]]]; } ll ans=0; for(re int i=n;i>=1;i--){ ans+=query(b[i]-1); ans%=mod; add(b[i],1); } cout<<ans; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」