2021年中国大学生程序设计大赛(哈尔滨)Gym 103447
B Magical Subsequence DP
题意:
给定一个序列 A,选择一个长为偶数的子序列 B,使得 B1+B2=B3+B4...,问这个满足条件的子序列最长能是多少。
代码
#include<cstring> #include<cstdio> #include<iostream> #include<algorithm> #include<vector> using namespace std; #define int long long const int N=1e5+10; int a[N]; vector<int> vec[220]; int dp[N][220][2];//dp[i][j]表示在前i个数中选择,对第i个数进行操作,每两个数加起来为j signed main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; vec[a[i]].push_back(i); } int maxx=2; for(int i=1;i<=n;i++) { for(int j=2;j<=200;j++) { dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]); int k=j-a[i]; if(k<=0) continue; if(vec[k].size()==0) continue; int pos=upper_bound(vec[k].begin(),vec[k].end(),i)-vec[k].begin();//找到第一个大于i的位置 if(pos==vec[k].size()) continue;//没有这样的位置 int p=vec[k][pos]; dp[p][j][1]=max(dp[p][j][1],dp[i][j][0]+2); } } for(int i=1;i<=n;i++) { for(int j=2;j<=200;j++) { maxx=max(dp[i][j][0],maxx); maxx=max(dp[i][j][1],maxx); } } cout<<maxx<<endl; return 0; }
E Power and Modulo
题意:
给你一个序列,第i个的值是$ 2^{i-1}\ mod Ma_{i}!= a_{i-1}*2a$的位置,则 ,如果没有这样的位置就无解。然后从前往后暴力判断一下是否符合即可,记得特判一下首项是否为0.
代码
#include <bits/stdc++.h> using namespace std; #define int long long #define pii pair<int, int> const int N =1e5 + 10; // const int M=1000000007; int n,m; // vector<int> ans; int a[N]; int num[N]; void init(){ num[0] = 1; for(int i = 1; i <= 35; i++){ // if(num[i - 1] * 2 > 1e9) break; num[i] = num[i - 1] * 2; } // cout << num[33] << endl; } void slove() { //init(); //cout <<"?" << num[64] << endl; int s = 0; map<int, int> mp; cin >> n; for(int i = 1; i <= n; i++){ cin >> a[i]; if(a[i] == 0) s ++; } if(s == n){ cout << 1 << endl; return; } bool flag = false; int mod = -1; int j = 0; int u = 1; for(int i = 1; i <= n; i++){ if(flag){ //if(mp.find(a[i]) == mp.end()) if(u * 2 % mod != a[i]){ cout << -1 << endl; //continue; return; } u = u * 2 % mod; } else{ if(num[i - 1] / 2 <= a[i] && a[i] != num[i - 1]){ cout << -1 << endl; return; } //if(mp.find()) if(a[i] != num[i - 1]){ mod = num[i - 1] - a[i]; flag = true; //j = i - 1; u = num[i - 1]; } } } if(mod == -1) cout << -1 << endl; else cout << mod << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t = 1; init(); cin >> t; while (t--) slove(); return 0; }
I Power and Modulo 二进制,思维,二分
题意
给你一个序列 ,你可以进行多次操作;
每次操作可以选择一个任意长度的序列 ,然后使得。问你最少多少次操作可以将序列变为零。
题解
可以发现
将A_n$ 分别求出来每个数的二进制位为 1 的数量
每次操作等价为消除下标从0开始的连续的1。
因此,问题等价为至少多少次操作将这些二进制的1消除掉。
问题也等价为:
将二进制存起来,从高位向低位变成一个不下降序列,此时最低位次数即所需次数
注意: 而为了使得操作次数最少,就要二进制数1的个数最少。
思路1:暴力,复杂度不明
从后往前遍历,如果发现当前位置大于前一个位置了,就匀到前一个位置些(匀出的个数*=2),以保证前一个位置个数 >= 当前位置个数。
进行若干遍此操作,便能保证低位到高位递减,同时 1 的个数最小化。
思路2:二分,复杂度明了
假设x次操作成立的话那么x+1次操作也一定成立,因此发现具有二段性可以二分。
和上面一样,我们从高位到低位枚举要将当前这一位的1全删掉需要的操作数(看看是否可以连续删即可),然后将当前这一位操作后剩下的给前面加上,再每一位都删除相应的数量即可,最后每一次的操作数累加起来就是res。
代码
#include<bits/stdc++.h> using namespace std; using ll = long long; ll ay[40]; int n; bool check(ll x){ if(ay[0]>x) return 0; ll a[40]; for(int i=0;i<=31;i++){ a[i]=ay[i]; } a[32]=0; for(int i=0;i<=31;i++){ if(i&&a[i]>a[i-1]||a[i]>x) return false; ll y = i?a[i-1]-a[i]:x-a[i]; a[i+1]-=y/2; a[i]+=y/2*2; } return true; } ll find() { ll l=0 , r=1e16; while (l < r) { ll mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1; } return l; } int main() { int _;scanf("%d",&_); while(_--){ memset(ay,0,sizeof ay); scanf("%d",&n); for(int i=1;i<=n;i++){ ll x;scanf("%lld",&x); for(int j=0;j<=31;j++){ ay[j]+=( (x>>j)&1 ); } } printf("%lld\n",find()); } return 0; }
J Local Minimum 水题
题意: 求出 的方格里面有几个数字是:不仅是同行最小,而且是同列最小。
思路:
先找出同行最小的位置,再找出同列最小的位置,判断有几个位置两个都满足
#include <bits/stdc++.h> using namespace std; // #define int long long #define pii pair<int, int> const int N =1010; // const int M=1000000007; int n,m; // vector<int> ans; int g[N][N]; int a[N],b[N]; void slove() { cin>>n>>m; int ans=0; for(int i=0;i<n;i++){ int cnt=0x3f3f3f3f; for(int j=0;j<m;j++){ cin>>g[i][j]; cnt=min(g[i][j],cnt); } a[i]=cnt; } for(int i=0;i<m;i++){ int cnt=0x3f3f3f3f; for(int j=0;j<n;j++){ cnt=min(g[j][i],cnt); } b[i]=cnt; } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(g[i][j]<=min(a[i],b[j])){ ans++; } } } cout<<ans<<endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t = 1; // cin >> t; while (t--) slove(); return 0; }
本文作者:kingwzun
本文链接:https://www.cnblogs.com/kingwz/p/16691149.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2021-09-13 vector用法