C. Road Optimization
题意:路上有很多标牌,路过这个标牌后,你每走一个单位长度的时间变为标牌上的数字。现在你可以忽视k个标牌,求从0走到 l 最少所需的时间。
解:是个dp。先套路地设 dp[i][j] 表示走到第 i 个标牌,忽视掉 j 个标牌所需的最短时间,好,考虑转移。加进来一个新的,考虑从前一个距离怎么变到现在的距离。已知新走一段的速度和前一个路牌有关,但我不确定前一个路牌有没有被我删掉。把速度写进状态里显然不好,有boom的风险。那就以前面每一个为起点开始走,取最小值。现在 j 定义为忽视,但从一个起点开始走是选择了这块路牌的意思,很别扭。不如把 j 定义为选择了 j 个路牌,最后减一下,就好写了。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 505 #define eps 0.00000001 #define inf 0x7fffffff //#define int long long int n,l,k; int d[maxx]={0},a[maxx]={0}; int dp[maxx][maxx]={0}; signed main() { // int T; // scanf("%d",&T); // while(T--){ // // } scanf("%d%d%d",&n,&l,&k); for(int i=1;i<=n;i++) scanf("%d",&d[i]); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=0;i<=n+1;i++) for(int j=0;j<=n+1;j++) dp[i][j]=inf; a[n+1]=0;d[n+1]=l;dp[1][1]=0; for(int i=2;i<=n+1;i++){ for(int j=1;j<=i;j++){ for(int s=1;s<=i-1;s++){ if(dp[s][j-1]!=inf) dp[i][j]=min(dp[i][j],dp[s][j-1]+a[s]*(d[i]-d[s])); } } } int ans=inf; for(int i=n+1;i>=n+1-k;i--) ans=min(ans,dp[n+1][i]); printf("%d\n",ans); return 0; } //dp[i][j]=dp[start][j-1]+a[start]*(d[i]-d[start]); //dp[i][j] 到第i个点,选择了j个点 j<=i
D. Binary Spiders

这题配图真是充满灵性,要我真看到14腿蜘蛛能吓飞出去
题意:给出n个数,选择其最大子集,使得子集内的数两两异或值大于等于k。
解:首先观察一下。如果比k大的位上有1,那答案肯定比k大(废话。0和1不同能产生1,因此在比k大的某一位上,所有数分成两拨,一拨是0,一拨是1。同一拨里根据下一位再分成两拨,就这样分到k的最高位。对于和k相同的位里,如果k这一位是1,那还要继续分成两拨;如果是0,那就不用分了,随便挑俩当答案。
看起来像个递归,还是个巨难写的递归。但真的有大佬写出来了,膜一下%%% 点击就膜
然后继续观察。对于任意大于0的k,其高于最高位的部分能分成2的某次幂拨。但由于数只有n个,所有不会炸。由于抽屉原理,在每一拨里最多选俩数。那问题就变成了从每一拨里选两个数,其异或值大于等于k。这里学了个新技能,01trie求最大异或值,复杂度nlogc,相当舒服xxx
第一次板子有点问题,第二个就好了,而且清零清得很优雅,一点也不T。
代码:
#include<bits/stdc++.h> using namespace std; #define ll long long #define maxx 300005 #define eps 0.00000001 #define inf 0x7fffffff //#define int long long int son[maxx<<5][2],idx; void init() { memset(son, 0, sizeof (int) * 2 * idx); idx = 0; } void insert(int x) { int cur = 0; for (int i = 30; i >= 0; i --) { int &to = son[cur][x >> i & 1]; to ?: to = ++ idx; cur = to; } } int query(int x) { int cur = 0, ans = 0; for (int i = 30; i >= 0; i --) { int to = son[cur][~ x >> i & 1]; to ? ans += 1 << i, cur = to : cur = son[cur][x >> i & 1]; } return ans; } int n,k; int a[maxx]; map<int,int> m1; map<int,vector<int> > group; vector<int> ans; signed main() { // int T; // scanf("%d",&T); // while(T--){ // // } scanf("%d%d",&n,&k); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); m1[a[i]]=i; } if(k==0){ printf("%d\n",n); for(int i=1;i<=n;i++) printf("%d ",i); return 0; } int length=0,b=k; while(b){ b/=2; length++; } for(int i=1;i<=n;i++){ int t=a[i]>>length; group[t].push_back(a[i]); } for(auto [i,vec]:group){ init(); int res=0; for(int x:vec){ insert(x); int y=query(x); res=max(res,y); if(y>=k){ ans.push_back(m1[x]); ans.push_back(m1[x^y]); break; } } if(res<k) ans.push_back(m1[vec[0]]); } if(ans.size()<2){ printf("-1\n"); return 0; } sort(ans.begin(),ans.end()); printf("%d\n",ans.size()); for(auto i:ans) printf("%d ",i); return 0; }
浙公网安备 33010602011771号