1900思维题
- https://codeforces.com/problemset/problem/1718/A2
题意:
- 给一个长度为
的数组 - 每次操作选择一个区间
,和一个整数x - 把区间所有的数异或上x,每次操作的的代价是
- 问把数组
全部变为 的最小代价是多少
思路:
- 观察发现
长度为1或2、3或4……的代价是相等的,而且还可以进一步推断,每一次的操作都可以分割成由1或2组成的小区间(在代价上数值相等) - 于是可见我们要分割的小区间长度为2的要尽可能的多(或者说每次操作都贪心少掉一次),才能达到代价最小
- 令
^ ^ ^ ,对于一个区间[L,R],当pre[L] == pre[R]时,容易发现这个区间操作的最小代价是R-L-1,否则是R-L - 于是题目就转化成了一个简单的线性dp,时间复杂度O(n^2)的做法呼之欲出
- 但是显然O(n^2)是不太够用的,我们需要优化,用一个map来记录上一个前缀异或和最近的位置,从这个位置进行状态转移即可
- 时间复杂度是O(n)
#include<bits/stdc++.h> #define debug1(a) cout<<#a<<'='<< a << endl; #define debug2(a,b) cout<<#a<<" = "<<a<<" "<<#b<<" = "<<b<<endl; #define debug3(a,b,c) cout<<#a<<" = "<<a<<" "<<#b<<" = "<<b<<" "<<#c<<" = "<<c<<endl; #define debug4(a,b,c,d) cout<<#a<<" = "<<a<<" "<<#b<<" = "<<b<<" "<<#c<<" = "<<c<<" "<<#d<<" = "<<d<<endl; #define debug5(a,b,c,d,e) cout<<#a<<" = "<<a<<" "<<#b<<" = "<<b<<" "<<#c<<" = "<<c<<" "<<#d<<" = "<<d<<" "<<#e<<" = "<<e<<endl; #define fr(t, i, n)for (long long i = t; i < n; i++) #define endl "\n" #define fi first #define se second //#define int long long using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII; typedef pair<LL,LL> PLL; //#pragma GCC optimize(3,"Ofast","inline") //#pragma GCC optimize(2) const int N = 1e5+10; int a[N],pre[N],f[N]; void solve() { int n;cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i]; pre[i] = pre[i-1] ^ a[i]; } map<int,int> idx; idx[0] = 0; //需要注意,刚开始的位置记录为0,0 for(int i = 1;i <= n;i ++) { f[i] = f[i-1] + 1; if(idx.count(pre[i])) { f[i] = min(f[i],f[idx[pre[i]]] + i - idx[pre[i]] - 1); } idx[pre[i]] = i; } cout << f[n] << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T = 1;cin >> T; while(T--){ //puts(solve()?"YES":"NO"); solve(); } return 0; } /* */
- 从这个O(n)的线性dp,能发现每个位置都是找上一个最近的相同异或前缀和的位置,那么我们可以直接省略掉这个dp的过程,直接用map记录
- 答案就是 n - x([L,R],pre[L] == pre[R]最多的数量)
#include<bits/stdc++.h> #define debug1(a) cout<<#a<<'='<< a << endl; #define debug2(a,b) cout<<#a<<" = "<<a<<" "<<#b<<" = "<<b<<endl; #define debug3(a,b,c) cout<<#a<<" = "<<a<<" "<<#b<<" = "<<b<<" "<<#c<<" = "<<c<<endl; #define debug4(a,b,c,d) cout<<#a<<" = "<<a<<" "<<#b<<" = "<<b<<" "<<#c<<" = "<<c<<" "<<#d<<" = "<<d<<endl; #define debug5(a,b,c,d,e) cout<<#a<<" = "<<a<<" "<<#b<<" = "<<b<<" "<<#c<<" = "<<c<<" "<<#d<<" = "<<d<<" "<<#e<<" = "<<e<<endl; #define fr(t, i, n)for (long long i = t; i < n; i++) #define endl "\n" #define fi first #define se second //#define int long long using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII; typedef pair<LL,LL> PLL; //#pragma GCC optimize(3,"Ofast","inline") //#pragma GCC optimize(2) const int N = 1e5+10; int a[N],pre[N]; void solve() { int n;cin >> n; for(int i = 1; i <= n; i++) { cin >> a[i]; pre[i] = pre[i-1] ^ a[i]; } set<int> st;st.insert(0); int ans = n; for(int i = 1;i <= n;i ++) { if(st.count(pre[i])) { ans --; st.clear(); } st.insert(pre[i]); } cout << ans << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T = 1;cin >> T; while(T--){ //puts(solve()?"YES":"NO"); solve(); } return 0; } /* */
分类:
动态规划
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析