A. 你也喜欢数学吗
题解:打表找规律找的
具体咋推得可以看【题解】2023河南萌新联赛第(一)场:河南农业大学_ICPC/CCPC/NOIP/NOI刷题训练题单_牛客竞赛OJ (nowcoder.com)
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+3;
const int mod=1000000007;
void solve() {
int n;
cin>>n;
int x=(__int128)(n)*((n+1))*((n+2))/6%mod;
cout<<x;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
// int t; cin>>t; while(t--)
solve();
return 0;
}
B Middle
题解:将数组每个数拆成2进制数字,线段树存每个数位进行位运算的值
每个数位的答案不是0开头进行运算就是1开头进行运算,具体可见代码注释
# include <bits/stdc++.h> using namespace std; const int N=1e5+10; int nums[N]; char s[N]; map<char,int>d; pair<int,int>transformations[3][2]; pair<int,int> tree[4*N][20]; pair<int,int>OP(pair<int,int>a,pair<int,int>b) { return make_pair(a.first ? b.second : b.first, a.second ? b.second : b.first); } void build(int idx,int l,int r,int bit) { if(l==r) { int v=nums[l]; int ops=d[s[l]]; tree[idx][bit]=transformations[ops][v>>bit&1];//这里就等于x当前bit位 op 当前数位 的值 } else { int mid=l+(r-l)/2; build(idx*2,l,mid,bit); build(idx*2+1,mid+1,r,bit); tree[idx][bit]=OP(tree[idx*2][bit],tree[idx*2+1][bit]);// 前一个区间值为x当前bit位 op l .....mid的值 //后一个为 0或者1 op mid+1 .....r的值 //所以 l....r当前bit的值为取决于 前一个区间xop...l...mid的值 } return ; } void update(int idx,int l,int r,int pos,int val,int bit) { if(l==r) { int ops=d[s[l]]; tree[idx][bit]=transformations[ops][val>>bit&1]; } else { int mid=l+(r-l)/2; if(pos<=mid) { update(idx*2,l,mid,pos,val,bit); } else { update(idx*2+1,mid+1,r,pos,val,bit); } tree[idx][bit]=OP(tree[idx*2][bit],tree[idx*2+1][bit]); } return ; } pair<int,int>query(int idx,int l,int r,int ql,int qr,int bit) { if(ql<=l&&r<=qr) { return tree[idx][bit]; } int mid=l+(r-l)/2; if(qr<=mid) { return query(idx*2,l,mid,ql,qr,bit); } if(ql>mid) { return query(idx*2+1,mid+1,r,ql,qr,bit); } return OP(query(idx*2,l,mid,ql,qr,bit),query(idx*2+1,mid+1,r,ql,qr,bit)); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); d['|']=0; d['^']=1; d['&']=2; transformations[0][0] = make_pair(0, 1);//如果当前数位为0,X数位为O 则第一个值为0 第二值为1 transformations[0][1] = make_pair(1, 1);//如果当前数位为1,X数位为O 则第一个值为1 第二值为1 因为1|任何数字都等于1,剩下同理。 transformations[1][0] = make_pair(0, 1); transformations[1][1] = make_pair(1, 0); transformations[2][0] = make_pair(0, 0); transformations[2][1] = make_pair(0, 1); int n; cin>>n; for(int i=0; i<n; ++i) { cin>>s[i]; } for(int i=0; i<n; ++i) { cin>>nums[i]; } for(int bit=0; bit<20; ++bit) { build(1,0,n-1,bit); } int q; cin>>q; for(int i=0; i<q; i++) { int op; cin>>op; if(op==1) { int pos,val; cin>>pos>>val; pos--; for(int bit=0; bit<20; ++bit) { update(1,0,n-1,pos,val,bit); } } else { int x,l,r; cin>>x>>l>>r; l--; r--; int res=0; for(int bit=0; bit<20; ++bit) { pair<int,int>tmp=query(1,0,n-1,l,r,bit); if(x>>bit&1) { res|=tmp.second<<bit;//是1就是后面的值 } else { res|=tmp.first<<bit; } } cout<<res<<'\n'; } } }
C. 硬币游戏
题解:其实你模拟一下过程就可以发现,如果当前全是1或者全是0的话,如果长度大于k就是后手赢,否则就是先手赢。然后我们将可以一下更改区间的值记作一段,如果是1或则是0
更改区间只有一段 则先手赢。然后思考发现,当后手赢的话只有以下可能
s==
"0101"
||s==
"1010"
||s==
"1100"
||s==
"0110"
||s==
"0011"
||s==
"1001"
其他都是平局
# include <bits/stdc++.h>
using namespace std;
int n,k;
string s;
int main() {
cin>>n>>k;
cin>>s;
int ans,ans1;
int cnt,cnt1;
cnt=cnt1=0;
ans=ans1=0;
int flag;
if(s[0]=='0') {
flag=0;
ans++;
} else {
flag=1;
ans1++;
}
for(int i=1; i<s.length(); i++) {
if(s[i]=='0'&&!flag) {
ans++;
if(ans>k) {
ans-=k;
cnt+=1;
}
} else if(s[i]=='0'&&flag) {
cnt1+=1;
ans1=0;
ans++;
flag=0;
} else if(s[i]=='1'&&flag) {
ans1++;
if(ans1>k) {
ans1-=k;
cnt1++;
}
} else if(s[i]=='1'&&!flag) {
flag=1;
cnt++;
ans=0;
ans1++;
}
}
if(ans) {
cnt+=1;
}
if(ans1) {
cnt1+=1;
}
if(cnt==0||cnt1==0) {
if(n>k)
{
cout<<"Bob"<<endl;
}
else{
cout<<"Alice"<<endl;
}
} else if(cnt==1||cnt1==1) {
cout<<"Alice"<<endl;
}
else if(s=="0101"||s=="1010"||s=="1100"||s=="0110"||s=="0011"||s=="1001") {
cout<<"Bob"<<endl;
return 0;
}
else {
cout<<":("<<endl;
}
}
D. 松鼠回家
题解 :正解是二分加最短路
但比赛时减枝也过了,有可能数据水了,代码如下;
# include <bits/stdc++.h> using namespace std; # define int long long const int M=2*1e5+10; int head[4*M],Next[3*M],edge[4*M],ver[4*M]; int cnt=0; int n,m,st,ed,h1; void add(int x,int y ,int z) { ver[++cnt]=y; edge[cnt]=z; Next[cnt]=head[x]; head[x]=cnt; } int a[M]; int book[M]; const int inf=1e18; int step=inf; void dfs(int x,int fa,int h,int v) { if(v>step) { return ; } if(x==ed) { step=min(step,v); return ; } for(int i=head[x]; i; i=Next[i]) { int y=ver[i]; int v1=edge[i]; if(y!=fa&&h-v1>=0&&!book[y]) { book[y]=1; dfs(y,x,h-v1,max(v,a[y])); book[y]=0; } } return ; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cin>>n>>m>>st>>ed>>h1; for(int i=1; i<=n; i++) { cin>>a[i]; } for(int i=1; i<=m; i++) { int x,y,z; cin>>x>>y>>z; add(x,y,z); add(y,x,z); } dfs(st,-1,h1,a[st]); if(step==inf) { cout<<"-1"<<endl; } else { cout<<step<<endl; } }
E. 动物朋友
题解: 题目问你由几种区间和可以等于m 我们从开头开始进行前缀和,如果当前和大于m
以后连续数字不可能等于m于是我们必须去掉前面的数字直到区间数字小与m 这样后面才有可能等于m
# include <bits/stdc++.h> # include <deque> using namespace std; const int N=1e6+10; char s[N]; int a[N]; deque<int>q; int main() { int n,m; cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i]; } int sum=0; int res=0; for(int i=1;i<=n;i++) { sum+=a[i]; q.push_back(a[i]); while(sum>=m&&q.size()) { if(sum==m) { res++; } sum-=q.front(); q.pop_front(); } } cout<<res<<endl; }
F. 松鼠排序
题解:如果 当前排列1不在首位,我们必须要先将1放在首位才能进行下面的置换,之后的数字同理
# include <bits/stdc++.h> using namespace std; const int N=1e6+10; char s[N]; int a[N]; map<int,int>d; int main() { int n; cin>>n; int sum=0; for(int i=1;i<=n;i++) { cin>>a[i]; d[a[i]]=i; } for(int i=1;i<=n;i++) { if(d[i]!=i) { sum+=1; d[a[i]]=d[i]; swap(a[d[i]],a[i]); d[i]=i; } } cout<<sum<<endl; }
G. Reverse
题意:思维题 结果最大就是求俩段全是1的长度最大和
# include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char s[N];
int a[N];
int main() {
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n;
cin>>n;
cin>>(s+1);
int cnt=0;
int res=0;
for(int i=1; i<=n; i++) {
if(s[i]=='1') {
cnt++;
} else if(s[i]=='0') {
if(cnt) {
a[res++]=cnt;
cnt=0;
}
}
}
if(cnt)
{
a[res++]=cnt;
}
sort(a,a+res);
reverse(a,a+res);
cout<<a[0]+a[1]<<endl;
}
H 迷宫探险
题解:最短路 就是最短路跑一遍就可以了,细节就是如果当前是弹簧,就跳,时间不加一,不然时间就加一计算。
具体看代码
# include <bits/stdc++.h>
using namespace std;
# define int long long
const int N=3015;
char s[N][N];
int book[N][N];
int book1[N][N];
const int inf=1e18;
int nex[4]= {1,-1,0,0};
int ney[4]= {0,0,1,-1};
signed main() {
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
cin>>s[i][j];
book[i][j]=inf;
}
}
int q1;
cin>>q1;
while(q1--) {
int x,y,z;
cin>>x>>y>>z;
book1[x][y]=z;
}
set<pair<int,pair<int,int>>>q;
q.insert({0,{1,1}});
book[1][1]=0;
while(!q.empty()) {
pair<int,pair<int,int>>d= *q.begin();
q.erase(q.begin());
if(s[d.second.first][d.second.second]=='*') {
for(int i=0; i<=3; i++) {
int x1=d.second.first+nex[i]*book1[d.second.first][d.second.second];
int y1=d.second.second+ney[i]*book1[d.second.first][d.second.second];
if(x1>=1&&x1<=n&&y1>=1&&y1<=m&&s[x1][y1]!='#') {
if(book[x1][y1]>d.first) {
q.erase({book[x1][y1],{x1,y1}});
book[x1][y1]=d.first;
q.insert({book[x1][y1],{x1,y1}});
}
}
}
continue ;
}
for(int i=0; i<=3; i++) {
int x1=d.second.first+nex[i];
int y1=d.second.second+ney[i];
if(x1>=1&&x1<=n&&y1>=1&&y1<=m&&s[x1][y1]!='#') {
if(book[x1][y1]>d.first+1) {
q.erase({book[x1][y1],{x1,y1}});
book[x1][y1]=d.first+1;
q.insert({book[x1][y1],{x1,y1}});
}
}
}
}
if(book[n][m]==inf) {
cout<<"-1"<<endl;
} else {
cout<<book[n][m]<<endl;
}
}
L 中位数
题解:其实就是建一个可以更改 数值并可以求前k最小值的线段树板子题,
只不过这个线段树是按值域建的,具体看代码。
# include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int a[N],b[N];
int tr[N*4];
void pushup(int u) {
tr[u]=tr[u<<1]+tr[u<<1|1];
}
void update(int u,int l,int r,int v,int y) {
if(l==r) tr[u]+=y;
else {
int mid=l+r>>1;
if(v<=mid) update(u<<1,l,mid,v,y);
else update(u<<1|1,mid+1,r,v,y);
pushup(u);
}
}
int query(int u,int l,int r,int k) {
if(l==r) return l;
int mid=l+r>>1;
if(k<=tr[u<<1]) return query(u<<1,l,mid,k);
return query(u<<1|1,mid+1,r,k-tr[u<<1]);
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
update(1,1,N,a[i],1);
}
for(int i=1; i<=m; i++) {
int x,y;
cin>>x>>y;
update(1,1,N,a[x],-1);
a[x]=y;
update(1,1,N,y,1);
cout<<query(1,1,N,(n+1)/2);
cout<<endl;
}
return 0;
}
I 松鼠采松果
题解:树上查分板子题 首先你要会lca 然后p[x]就是当前节点到根节点所有边之和,求x到y路径权值和是p[x]+p[y]-p[lca(x,y)]*2.至于p[x]怎么求的就是利用差分求和得到的,你可以根据下面代码模拟一下树上差分的过程。
# include <bits/stdc++.h> using namespace std; # define int long long const int N=4*5*1e5+10; int n,m,tot,ans,p[N],f1[N],lin[N],f[N][25],d[N],vis[N]; int head[N],edge[N],ver[N],Next[N]; int cnt=0; void add(int a,int b,int c) { ver[++cnt]=b; edge[cnt]=c; Next[cnt]=head[a]; head[a]=cnt; } void bfs() { queue<int>q; q.push(1); d[1]=1; while(q.size()) { int x=q.front(); q.pop(); for(int i=head[x]; i; i=Next[i]) { int y=ver[i]; if(d[y]) { continue ; } p[y]+=edge[i]; p[x]-=edge[i]; d[y]=d[x]+1; f[y][0]=x; for(int j=1; j<=23; j++) { f[y][j]=f[f[y][j-1]][j-1]; } q.push(y); } } } int lca(int x,int y) { if(d[x]>d[y]) { swap(x,y); } for(int i=23; i>=0; i--) { if(d[f[y][i]]>=d[x]) { y=f[y][i]; } } if(x==y) { return x; } for(int i=23; i>=0; i--) { if(f[x][i]!=f[y][i]) { x=f[x][i],y=f[y][i]; } } return f[x][0]; } void dfs(int x) { vis[x]=1; for(int i=head[x]; i; i=Next[i]) { int y=ver[i]; if(vis[y]) { continue ; }; p[y]+=p[x]; dfs(y); } } void dfs1(int x) { vis[x]=1; for(int i=head[x]; i; i=Next[i]) { int y=ver[i]; if(vis[y]) { continue ; }; dfs1(y); p[x]+=p[y]; } } signed main() { int q; cin>>n>>m>>q; for(int i=1; i<n; i++) { int x,y,z; cin>>x>>y>>z; add(x,y,z); add(y,x,z); } bfs(); for(int i=1; i<=m; i++) { int x,y,z; cin>>x>>y>>z; p[x]+=z; p[y]+=z; p[lca(x,y)]-=2*z; } dfs1(1); memset(vis,0,sizeof(vis)); dfs(1); for(int i=1; i<=q; i++) { int x,y; cin>>x>>y; cout<<p[x]+p[y]-2*p[lca(x,y)]<<endl; } }
J 合唱比赛
题解:最高分就是去掉一个最低分的平均值,最低分就是去掉一个最高分的平均值
# include <bits/stdc++.h> using namespace std; const int N=1e6+10; char s[N]; double a[N]; int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; } sort(a+1,a+n+1); double r,l; r=l=0; for(int i=2;i<=n;i++) { r+=a[i]; } r=r/(n-1); for(int i=1;i<=n-1;i++) { l+=a[i]; } l=l/(n-1); printf("%.6lf %.6lf",l,r); }
K 以撒和隐藏房间
题解:根据题意对于每个是墙的根据题意判断就行,坑点就是普通房间就只能是3个
# include <bits/stdc++.h>
using namespace std;
const int N=2000;
char s[N][N];
int n,m;
int nex[4]= {1,-1,0,0};
int ney[4]= {0,0,1,-1};
bool check(int x,int y) {
int flag=0;
int res=0;
for(int i=0; i<=3; i++) {
int x1=x+nex[i];
int y1=y+ney[i];
if(x1>=1&&x1<=n&&y1>=1&&y1<=m) {
if(s[x1][y1]=='1') {
res++;
}
if(s[x1][y1]=='2') {
flag=1;
}
}
}
if(res==3&&!flag) {
return 1;
} else {
return 0;
}
}
int main() {
cin>>n>>m;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
cin>>s[i][j];
}
}
int res1=0;
for(int i=1; i<=n; i++) {
for(int j=1; j<=m; j++) {
if(s[i][j]=='0') {
if(check(i,j)) {
res1++;
}
}
}
}
if(res1)
{
cout<<"YES"<<endl;
cout<<res1<<endl;
}
else
{
cout<<"NO"<<endl;
}
}