2024牛客寒假算法集训营4 (已更新:B-E)
1.CF-925(已更新:D-F)2.2024牛客寒假算法基础集训营33.CF-926(已更新:B-C)4.CF-927(已更新:B C E)5.CF-928(已更新:B C D E)
6.2024牛客寒假算法集训营4 (已更新:B-E)
7.CF EDU-162 (已更新:A-C+D的代码)8.At-abc3429.蒟蒻的补档题(长期更新)10.CF-929(已更新:B-E)11.CF-931(已更新:AB代码)12.PowerOj 2024-康复赛 (待更新)13.CF-932(已更新 A B)14.矩阵快速幂15.CF-933(已更新:B-D)16.数论分块17.CF-Edu-163(已更新:A B)18.CF-936(AB)19.AT-abc347(C-E)20.CF-938(C-E)21.CF-943(已更B-E,G1)22.CF-945(已更A,B)23.CF-956(A-D)24.CF-957(D-E)25.CF-959(C-E)26.Codeforces Round 967 (Div. 2)-D27.AtCoder Beginner Contest 396 (E-F)28.Codeforces Round 1008 (Div. 2) (C-D)2024牛客寒假算法集训营4
B
看似是博弈论,实际上是推结论
代码实现
每堆石子不可操作时数量都为1,举例可以推出,每堆石子的可操作数都为a[i]-1,这样一来所有石子的可操作数就能算出来,为奇数时是一个,否则是另一个
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,x,sum=0;cin>>n;
for(int i=0;i<n;i++){
cin>>x;
sum+=x-1;
}
if(sum&1) cout<<"gui";
else cout<<"sweet";
return 0;
}
C
对我来说有点难想的模拟题-^-
代码实现
我自己赛时写的是不改变原数组,模拟目标点(x,y)的移动,倒着读入指令,注意只处理与(x,y)点在同一行或同一列的指令
指令的行向右移,则y--
3 3 2 2
abc
def
ghi
1 2
1 1
2 2
(x,y)的变化:
(2,2)->(1,2)—>(1,1)
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int N=2e2+5;
char a[N][N];
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m,p,q,x,y;cin>>n>>m>>x>>y;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
cin>>p>>q;
vector<pair<int,int>>v;
int op,l;
for(int i=0;i<q;i++){
cin>>op>>l;
v.push_back({op,l});
}
while(p--){
for(int i=q-1;i>=0;i--){
int e=v[i].first,r=v[i].second;
if(!(e==1&&r==x||e==2&&r==y)){
continue;
}
if(e==2&&r==y){
x--;
if(x==0) x=n;//移动到边界要更新
}
else if(e==1&&r==x){
y--;
if(y==0) y=m;
}
}
}
cout<<a[x][y];
return 0;
}
贴一个模拟的做法~
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int N=2e2+5;
char a[N][N];
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m,p,q,x,y;cin>>n>>m>>x>>y;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
cin>>p>>q;
vector<pair<int,int>>v;
int op,l;
for(int i=0;i<q;i++){
cin>>op>>l;
v.push_back({op,l});
}
while(p--){
for(auto it:v){
int op=it.first,r=it.second;
if(op==1){
//这里就是当时没想出来的做法(⊙﹏⊙)
int tp=a[r][m];
for(int i=m;i>=2;i--){
a[r][i]=a[r][i-1];
}
a[r][1]=tp;
}
else{
int tp=a[n][r];
for(int i=n;i>=2;i--){
a[i][r]=a[i-1][r];
}
a[1][r]=tp;
}
}
}
cout<<a[x][y];
return 0;
}
D
可以说要只要是要用到数学公式或者涉及基础数论的题,我赛时就做不了一点⊙﹏⊙)——这道题就是(⊙﹏⊙)
数组的最大公因数g,b[i]=a[i]/g,满足:a[1]+……a[n]=g*(b[1]+……b[n])=sum,g的变化来自b[i],同时sum(b[i])>=n(也就是每个b[i]为1的情况)
如sum(2 2 4 8)->2*sum(1 1 2 4)->4乘sum(1 1 1 1)
代码实现
所以我们可以枚举sum的因子i,若满足sum/i>=n,则ans++
补充:如何枚举与遍历一个数的因子:
int n;cin>>n; set<int>s; for(int i=1;i<=n/i;i++){ if(n%i==0){ s.insert(i); if(i*i!=n){ s.insert(n/i); } } } cout<<s.size()<<endl; for(auto i:s) cout<<i<<" ";
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int N=2e5+5;
int a[N];
int gcd(int a,int b){
if(b==0) return a;
else return gcd(b,a%b);
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;cin>>n;
int sum=0,res=1;
rep(i,1,n){
cin>>a[i];
sum+=a[i];
if(i==1){
res=a[i];
}
else res=gcd(a[i-1],res);
}
int ans=0;
for(int i=1;i<=sum/i;i++){
if(sum%i==0&&sum/i>=n){
ans++;
if(i*i!=sum&&sum/(sum/i)>=n) ans++;
}
}
cout<<ans<<endl;
return 0;
}
E
其实就是贪心的技巧……但赛时就没想明白
- 要使答案最大,应该能分组就尽量分组,因为如果一个数就算加到当前组里,它也不可能加到后面的组里,因此我们可以用前缀和实现这一步
- 如何判断当前组的和是k的倍数?只要这个组的左端点-1与右端点的前缀和模k相等即可
如
1 1 4 5 1 4 前缀和0 1 2 6 11 12 16 ^ ^ ^ 得到分组(1,1,4),(5,1)
代码实现
可以用set存前缀和模k的值(即可能的左端点-1),先在set 里加入0,遍历前缀和数组,存下这个值,在这之前还要判断这个值是否在set里出现过,如果出现过,说明找到了一个分组的右端点,就要清空set,同时插入这个右端点当作可能的左端点-1
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define db(x) cout<<x<<" "<<endl;
#define _db(a,n) for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
#define mem(a) memset(a,0, sizeof(a))
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int N=2e5+5;
int a[N];
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,k,x;cin>>n>>k;
rep(i,1,n){
cin>>x;
a[i]=a[i-1]+x;
}
set<int>s;
s.insert(0);
int ans=0;
rep(i,1,n){
if(s.count(a[i]%k)){
ans++;
s.clear();
}
s.insert(a[i]%k);
}
cout<<ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】