H.两难抉择(简单,找出最大数执行两种操作取最大求和即可)
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=1e6+10; int n,m,t; int a[N]; void solve(){ cin>>n; for(int i=0;i<n;i++)cin>>a[i]; sort(a,a+n); int sum=0; a[n-1]=max(a[n-1]+n,a[n-1]*n); for(int i=0;i<n;i++)sum+=a[i]; cout<<sum<<endl; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int _; _=1; while(_--)solve(); return 0; }
A.造数(简单,根据题意每次执行最优策略即可,显然数越大选择×2操作总操作数会更小,注意奇偶转换)
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=5e6+10; int n,m,t; void solve(){ cin>>n; int ans=0; if(n==0){ cout<<0; return; }else if(n==1||n==2){ cout<<1; return; } while(n>=2){ if(n&1){ n-=1; ans++; } n>>=1; ans++; } cout<<ans<<endl; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int _;_=1; while(_--)solve(); return 0; }
K.图上计数easy(简单,显然删除所有边后重组点化为两个连通块,相当于a+b=k,求a*b的最大值)
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=5e6+10; int n,m,t; void solve(){ cin>>n>>m; while(m--){ int a,b; cin>>a>>b; } if(n&1){ cout<<(n/2)*(n-n/2)<<endl; }else cout<<(n/2)*(n/2)<<endl; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int _; _=1; while(_--)solve(); return 0; }
I.除法移位(简单,暴力枚举把最大的数放到第一个需要的次数即可)
#include<bits/stdc++.h> //#define int long long #define endl '\n' using namespace std; const int N=5e6+10; int a[N]; int n,m,t; void solve(){ cin>>n>>t; int maxs=0; for(int i=1;i<=n;i++)cin>>a[i]; maxs=a[1]; int cost=0,temp=t; for(int i=n;i>=1;i--){ if(a[i]>maxs){ maxs=a[i]; cost=temp-t+1; } t--; if(t==0)break; } cout<<cost; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int _; _=1; pre(); while(_--)solve(); return 0; }
F.两难抉择新编(稍简单,H的改编题,异或小技巧+暴力枚举可过,注意到只操作一个数并与其他数求异或和,可以先求出初始全部异或和res,再利用消除一个数的异或等于再异或上它本身得到res‘,枚举要改变的那个数,并枚举执行两种操作后再与res’异或取最大值)
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=5e6+10; int a[N]; int n,m,t; void solve(){ cin>>n; int res=0,ans=0; for(int i=1;i<=n;i++){ cin>>a[i]; res^=a[i]; } int tt=res; for(int i=1;i<=n;i++){ res=tt; res^=a[i]; for(int j=1;j<=n/i;j++){ ans=max(ans,max(res^(a[i]+j),res^(a[i]*j))); } } cout<<ans; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int _;_=1; while(_--)solve(); return 0; }
C.有大家喜欢的零食吗(稍中等,洛谷对应绿题板子,学过的知道是标准模板题求二分图最大匹配数,赛时没看可惜了)
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; int e[N],ne[N],idx,h[N],n,m,t; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } int st[N]; int match[N]; bool find(int x){//检查X是否有匹配 for(int i=h[x];~i;i=ne[i]){ int j=e[i]; if(!st[j]){ st[j]=1; if(match[j]==0||find(match[j])){ match[j]=x; return true; } } } return false; } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); memset(h,-1,sizeof h); cin>>t; for(int i=1;i<=t;i++){ int x;cin>>x; while(x--){ int a; cin>>a; add(i,a); } } int res=0; for(int i=1;i<=t;i++){ memset(st,0,sizeof st); if(find(i))res++; } if(t==res)cout<<"Yes"; else{ cout<<"No"<<endl<<t-res<<endl; } return 0; }
G.旅途的终点(稍中等,类似于一个模拟,由于线路固定,有k次反悔过程,可以用优先队列维护,题解给的是小根堆,我用大根堆wa了好几发才过。。。还是太菜了,思路就是不管怎样先消耗生命值,并加入大根堆,如果发现生命值<=0了,那么还有k次反悔机会,把大根堆里最大的消耗过的生命值加回来,k--,如果最后仍然生命值小于等于0且无力回天了则直接输出答案)
#include<bits/stdc++.h> #define endl '\n' #define int long long #define ll long long #define ull unsigned long long using namespace std; const ll N=2e5+10; priority_queue<ll,vector<ll>>q; int n,m,k; ll a[N]; signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); cin>>n>>m>>k; for(int i=1;i<=n;i++)cin>>a[i]; if(k>=n){ cout<<n; return 0; } for(int i=1;i<=n;i++){ q.push(a[i]); m-=a[i]; if(m<=0){ if(k>=1){ m+=q.top(); q.pop(); k--; if(m<=0){ cout<<i-1; return 0; } }else{ cout<<i-1; return 0; } } } cout<<n; return 0; }
D.小蓝的二进制询问(中等,找规律数学题,找前x个数第i位上1的个数,统计所有的位数上的1,数据范围太大暴力肯定tle,运用位运算似乎有模板,算是学到新知识了)
#include<bits/stdc++.h> #define int long long #define endl '\n' using namespace std; const int N=5e6+10,mod=998244353; int dp[N],a[N]; int n,m; map<int,int>mp; int counts(int k,int x){//前k个数的第x位上1的和 int t1=1ll<<(x+1); int t2=t1/2; int ans=0; ans=(k+1)/t1*t2; int r=(k+1)%t1; r-=t2; if(r>0)ans+=r; return ans; } void solve(){ int t;cin>>t; while(t--){ int ans=0; int l,r; cin>>l>>r; for(int i=61;i>=0;i--){//long long从61位,int从31位起 int p=(counts(r,i)%mod-counts(l-1,i)%mod+mod)%mod; ans=(ans%mod+p%mod)%mod; } cout<<ans<<endl; } } signed main(){ ios::sync_with_stdio(0),cin.tie(0),cout.tie(0); int _; _=1; //pre(); while(_--)solve(); return 0; }
此处贴上来自牛客寒假集训营里大佬的板子,我纯找规律就推了半天,0~x的第i位上都有一个大周期2^(i+1),小周期2^i,这个周期里有2^k个1,x%=大周期,x-=小周期,如果x仍大于0说明超过了半个小周期,则又有x个1.。。。。。把0~15的二进制表示出来按位找规律进行了
总结:做题不补题等于白做,个人评价难度不等于实际难度,题出的很好,为出题人点赞,&我惨烈补题记录,还是菜就多练