2026牛客寒假算法基础集训营1 9/12
L. Need Zero
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
if((n*i)%10 == 0){
cout<<i<<endl;
return;
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
// cin>>ct;
while(ct--){
solve();
}
}
K. Constructive
只有 \(n=1\) 或 \(n=3\) 时,有解,更大的 \(n\) 连乘太大了
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
if(n==1){
cout<<"YES\n1\n";
}
else if(n==3){
cout<<"YES\n1 2 3\n";
}
else{
cout<<"NO\n";
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
C. Array Covering
显然,可以把 \([2,n-1]\) 中的所有数都变成整个序列的最大值
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
int mx=*max_element(a.begin()+1,a.end());
for(int i=2;i<n;i++){
a[i]=mx;
}
cout<<accumulate(a.begin()+1,a.end(),0ll)<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--) solve();
return 0;
}
E. Block Game
等价于把万能方块放到 \(a[n+1]\) 的位置。
然后找两个相邻位置和的最大值即可,注意 \(i=1\) 和 \(i=n+1\) 也算是相邻
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;
void solve(){
int n,k;
cin>>n>>k;
vector<int> a(n+1);
for(int i=1;i<=n;i++){
cin>>a[i];
}
int ans=max(a[1]+k,a[n]+k);
for(int i=2;i<=n;i++){
ans=max(ans,a[i-1]+a[i]);
}
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--) solve();
return 0;
}
B. Card Game
找到 \(b\) 数组的最大值 \(mn\),显然,\(a\) 数组中的所有比 \(mn\) 大的数字,都可以被消除,而所有比 \(mn\) 小的数字,都不能被消除
所以,把所有比 \(mn\) 大的数字放在前面,小的数字放到后面即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1),b(n+1),fact(n+1);
fact[0]=1;
for(int i=1;i<=n;i++){
cin>>a[i];
fact[i]=fact[i-1]*i%mod;
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
int mn=*min_element(b.begin()+1,b.end());
int cnt=0;
for(int i=1;i<=n;i++){
if(a[i]>mn) cnt++;
}
cout<<fact[cnt]*fact[n-cnt]%mod<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--){
solve();
}
}
G. Digital Folding
当 \(l=r\) 时,答案固定
当 \(l\) 的位数,比 \(r\) 的位数小时:
如果 \(r=1000..00\) 这样的,答案一定是 \(99..99\),长度是 \(r\) 的位数 -1
否则,答案的长度一定是 \(r\) 的位数
所以,可以在此时,把 \(l\) 设置为 \(100.00\),长度为 \(r\) 的位数
此时, \(l,r\) 的位数一定相等。
注意,现在还没有进行反转,所以要要尽可能让靠后的位的数值变大
从前往后循环,\(l,r\) 前面完全相同的位是动不了的,知道某一个位不同,就可以让这一位的数值 -1,然后让后面的位都变成 \(9\)
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 1e9+7;
int len(int x){
int res=0;
while(x){
x/=10;
res++;
}
return res;
}
string rv(int x){
string t;
while(x){
int val=x%10;
t.push_back((char)val+'0');
x/=10;
}
return t;
}
string str(int x){
auto s=rv(x);
reverse(s.begin(),s.end());
return s;
}
void solve(){
int l,r;
cin>>l>>r;
if(l==r){
string s=rv(l);
int p=0;
for(int i=0;i<s.size();i++){
if(s[i]!='0'){
p=i;
break;
}
}
for(int i=p;i<s.size();i++){
cout<<s[i];
}
cout<<endl;
return;
}
if(len(l)!=len(r)){
if(len(r)!=len(r-1)){
for(int i=1;i<=len(r-1);i++){
cout<<9;
}
cout<<endl;
return;
}
else{
l=1;
for(int i=1;i<len(r);i++){
l*=10;
}
}
}
string a=str(l),b=str(r);
//现在答案的长度已经固定了
int pos=-1,f=0,nd=0;
string ans;
for(int i=0;i<a.size();i++){
if(f && b[i]<'9'){
ans.push_back('9');
nd=1;
continue;
}
if(a[i]==b[i]){
ans.push_back(a[i]);
}
else{
if(pos==-1){
pos=i;
f=1;
}
ans.push_back(b[i]);
}
}
if(nd) ans[pos]--;
reverse(ans.begin(),ans.end());
cout<<ans<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--) solve();
return 0;
}
H. Blackboard
核心性质:如果两个数与运算结果为零,则或运算和加法的结果相同。
否则,或运算的结果一定比加法小,原因是或运算没有进位
设 \(f[i]\) 表示,只考虑前 \(i\) 个数有多少种合法的情况
对于每一个 \(i\),枚举可以进行多少次连续的或运算,即可以连续或上前面多少个数,满足或运算和加法结果一样。
最多 \(32\) 个正整数。因为只有 \(32\) 位,所以或上 \(32\) 个数后,一定有一位的 \(1\) 会重复
因为数组中有 \(0\),所以需要预处理出来,每个数前面最近的正整数在哪里
对于 \(f[i]\),如果前面最长可以或上位置 \(pos+1\),则 \(f[i]\) 等于 \(pref[i-1]-pref[pos-1]\),即 \(f[i-1]\) 到 \(f[pos]\) 的和
(等价于枚举,往前连续的或运算后,第一个加法前的位置,而这个位置的答案就是 \(f[j]\))
其中,\(pref\) 是 \(f\) 的前缀和数组
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
using ll=long long;
using pii=pair<int,int>;
const ll inf = 1e18;
const int mod = 998244353;
void solve(){
int n;
cin>>n;
vector<int> a(n+1);
vector<int> lst(n+1);
int now=0;
for(int i=1;i<=n;i++){
cin>>a[i];
lst[i]=now;
if(a[i]) now=i;
}
vector<int> f(n+1),s(n+1);
f[0]=1,s[0]=1;
for(int i=1;i<=n;i++){
int now=i,val=0;
while(now && (val&a[now])==0){
val|=a[now];
now=lst[now];
}
if(now==0) f[i]=s[i-1];
else f[i]=(s[i-1]-s[now-1]+mod)%mod;
s[i]=(f[i]+s[i-1])%mod;
}
cout<<f[n]<<endl;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
int ct=1;
cin>>ct;
while(ct--) solve();
return 0;
}
D. Sequence Coloring
二分,懒得写了
I. AND vs MEX
如果 \(l=0\),则答案就是 \(r+1\)
设 \(l,r\) 的最高位 \(1\) 的位置分别为 \(b1,b2\)
如果 \(b1=b2\),则无论如何都搞不出 \(0\),答案为 \(0\)
如果 \(b1+1<b2\) 则可以使用 \((1<<b2)-1\) 和其他数,容易的把 \(0-(l-1)\) 与出来
如果 \(b1+1=b2\):
设 \(x~=~(1<<b2)-1\),让 \(x\) 异或 \(x+1,x+2,...,r\),可以得到 \(0,1,...,r-x-1\),则此时第一个与不出来的数为 \(r-x\)
如果 \(r-x>=l\),则答案为 \(r+1\)
刚刚是从 \(x\) 往上异或,接下来从 \(x\) 往下异或,注意可以异或多个数。找到 \(l\) 中最高的和 \(x\) 不同的位,从这一位开始都可以是 \(0\)
比较这两个数,判断答案是 \(r+1\) 还是 \(r-x\)

浙公网安备 33010602011771号