C++算法训练第八天
C++算法训练第八天
以下为牛客挑战
今日收获
学习到了ksm的写法
int ksm(int p,int q,int mod){
int result=1;
p=p%mod;
while (q>0){
if(q&1){//
result=(1ll*result*p)%mod;
}
q=q>>1;
p=(1ll*p*p)%mod;
}
return result%mod;
}
知道了滚动数组
先有一个数组,然后在操作时候弄一个一样的数组,dp转移完成之后,直接赋值回最先的数组。为了节省空间。
练习了一下BFS搜图
【算法竞赛知识点-数学】:快速幂_哔哩哔哩_bilibili
牛客周赛 Round 127
(36条未读私信) 牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)
Get The Number
A-Get The Number_牛客周赛 Round 127 (nowcoder.com)

解题代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m,x;
cin>>n>>m>>x;
if(x==(n+m)||(n-m)==x ||((n/m==x)&&(m*x==n))){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
return 0;
}
Sudoku
B-Sudoku_牛客周赛 Round 127 (nowcoder.com)

2
1 2 3 4
3 4 1 2
2 1 4 3
4 3 2 1
1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
YES
NO
解题代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];
void solve(){
int m[5][5]={0};
for(int i=1;i<=4;i++){
for(int j=1;j<=4;j++){
cin>>m[i][j];
}
}
for(int i=1;i<=4;i++){
set<int>str;
for(int j=1;j<=4;j++){
str.emplace(m[i][j]);
}
if(str.size()!=4){
cout<<"NO"<<endl;
return;
}
}
for(int i=1;i<=4;i++){
set<int>str;
for(int j=1;j<=4;j++){
str.emplace(m[j][i]);
}
if(str.size()!=4){
cout<<"NO"<<endl;
return;
}
}
for(int i=1;i<4;i+=2){
for(int j=1;j<4;j+=2){
int sum=0;
sum=m[i][j]+m[i][j+1]+m[i+1][j]+m[i+1][j+1];
if(sum!=10){
cout<<"NO"<<endl;
return;
}
}
}
cout<<"YES"<<endl;
};
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
TESTS{
solve();
};
return 0;
}
Carry The Bit
C-Carry The Bit_牛客周赛 Round 127 (nowcoder.com)

3
3749
105
999
4000
110
1000
我们可以用string去存储,一共才2x10五次方
直接string去存储,找到第一个大于5的数,然后剩下的按格式输出就行了,没找到就把最后的变成0;
解题代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];
void solve(){
string s;
cin>>s;
s='0'+s;
int p=-1;
int l=s.size();
for(int i=1;i<l;i++){
int m=s[i]-'0';
if(m>=5){
p=i;
break;
}
}
cout<<p<<endl;
if(p==-1){
for(int i=1;i<l-1;i++){
cout<<s[i];
}
cout<<0<<endl;
}else{
if(p==1){
cout<<1;
for(int i=1;i<l;i++){
cout<<0;
}
cout<<endl;
return;
}
for(int i=1;i<p-1;i++){
cout<<s[i];
}
cout<<(s[p-1]-'0')+1;
for(int i=p;i<l;i++){
cout<<0;
}
}
cout<<endl;
};
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
TESTS{
solve();
};
return 0;
}
Permutation² Counting
D-Permutation² Counting_牛客周赛 Round 127 (nowcoder.com)

示例1
2
6
1 2 2 1 3 1
5
1 1 2 2 4
6
2
我们看到这个和顺序没有关系,我们可以直接先排序。然后统计个数,因为这个是必须按照1-i这样的,所以我们对于这一次,就是选出两个i的数方法,去和上次的x,再加就行了

解题代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=998244353;
int a[N],b[N],c[N];
void solve(){
int n;
cin>>n;
vector<int>cnt(n+1);
for(int i=1,x;i<=n;i++){
cin>>x;
if(x<1||x>n){
continue;
}
cnt[x]++;
}
int pre=1;
int ans=0;
//我们去枚举i,因为,我们知道n的活动范围就是在1-n的,当为1,时候就是冲cnt[i]个数中排列组合一下,选两个(cnt[i]-1)*(cnt[i])/2
for(int i=1;i<=n;i++){
pre*=((cnt[i]-1)*cnt[i]/2%mod);
pre%=mod;
ans=(ans+pre)%mod;
}
cout<<ans<<endl;
};
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
TESTS{
solve();
};
return 0;
}
Balanced 01-String
E-Balanced 01-String_牛客周赛 Round 127 (nowcoder.com)

2
0?1
????
0
8
思维题。
题目要我们求相同的对数,那我们直接反过来求不同的对数,然后用1-n一共n-1对减去相同的对数就可以判断不同的对数的奇偶性。
就是s[i]!=s[i+1];
这个不同可以用异或来
s[i]^s[i+1],如果相同直接是0,如果不同不为0;
然后我们要去相加这些数。
结果相加,看看不同的奇偶性。

这个可以化简为,
s[0]^s[1]^s[1]^s[2]^s[2]^s[3]........s[n-2]^s[n-1]
由异或的性质相同异或的为0,0……其他等于本身。
化简为
s[0]^s[n-1]
所以只要判断这两个数的就行了,
最后用个去
((n-1)%2-(s[0]^s[n-1]))%2==0
这个,然后个数我们只需要看里面的2的cnt次方个就行了。
s[0]与s[n-1]分3种情况讨论就行了
- 没有?全是其他的。直接判断一下就行了。
- 有一个那肯定可以组成一个
- 有两个可以组成两个。
最后chen中间的个数。
代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
int ksm(int p,int q,int mod){
int result=1;
p=p%mod;
while (q>0){
if(q&1){
result=(1ll*result*p)%mod;
}
q=q>>1;
p=(1ll*p*p)%mod;
}
return result%mod;
}
const int N=2e5+10,M=1e3+10,mod=998244353;
int a[N],b[N],c[N],pre[N];
void solve(){
string s;
cin>>s;
int m=0;
int n=s.size();
if(n==1){
if(s[0]=='?'){
cout<<2<<endl;
return;
}else{
cout<<1<<endl;
return;
}
}
for(int i=1;i<s.size()-1;i++){
if(s[i]=='?'){
m++;
}
}
int cnt=ksm(2,m,mod);
if(s[0]!='?'&&s[n-1]!='?'){
if(((n-1)%2-(s[0]^s[n-1]))%2==0){
cout<<cnt<<endl;
}else{
cout<<0<<endl;
}
}else{
if(s[0]=='?'&&s[n-1]=='?'){
cout<<(2*cnt)%mod<<endl;
}else{
cout<<cnt<<endl;
}
}
};
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
TESTS{
solve();
};
return 0;
}
dp+滚动数组求解
我们定义一个发f[0/1][0/1];
表示当前,为奇数或者偶数的状态下,当前位置为0/1的方案数,转移就是,我们根据你一个方案来转移,一共四个状态,
判断单前位置不等于1,那我们不用管,先假设选的就是0;,然后转移
g[0][0]和g[1][0],就可以得到,因为我当前位置已经知道了,我们可以看前面为0,1的时候的次数,和奇偶性来判断g[0][0],这个数。
g[0][0]=f[1][0]+f[0][1];
g[1][0]=f[1][1]+f[0][0];
以此类推后面的。
结果为,f[0][1]+f[0][0]
代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=998244353;
int a[N],b[N],c[N],pre[N];
void solve(){
string s;
cin>>s;
int n=s.size();
s=" "+s;
vector<vector<int>>f(2,vector<int>(2));
if(s[1]=='?'){
f[0][1]=1;
f[0][0]=1;
}else if(s[1]=='1'){
f[0][1]=1;
}else{
f[0][0]=1;
}
for(int i=2;i<=n;i++){
vector<vector<int>>g(2,vector<int>(2));
if(s[i]!='0'){
g[0][1]=f[0][0]+f[1][1];
g[1][1]=f[1][0]+f[0][1];
}
if(s[i]!='1'){
g[0][0]=f[1][0]+f[0][1];
g[1][0]=f[1][1]+f[0][0];
}
//处理数据。mod;
for(int j=0;j<2;j++){
for(int k=0;k<2;k++){
g[j][k]%=mod;
}
}
f=g;
}
cout<<(f[0][0]+f[0][1])%mod<<endl;
};
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
TESTS{
solve();
};
return 0;
}
Matrix Coloring
BFS搜索
F-Matrix Coloring_牛客周赛 Round 127 (nowcoder.com)

2
3
010
101
010
5
00000
01110
01000
01010
01110
111
111
111
00000
01110
01110
01110
01110
我们可以知道这个就是一个简单的BFS,但是这个是先把图先扫一边,把满足条件的先丢进栈中,然后再根据改的,慢慢扩散开来,已达到最后的效果。
解题代码
#include<bits/stdc++.h>
#define int long long
#define lll __uint128_t
#define PII pair<int ,int>
#define endl '\n'
using namespace std;
#define yn(ans) printf("%s\n", (ans)?"Yes":"No");//快速打印
#define YN(ans) printf("%s\n", (ans)?"YES":"NO");
#define REP(i, e) for (int i = 0; i < (e); ++i)
#define REP1(i, s, e) for (int i = (s); i <=(e); ++i)
#define TESTS int t; cin >> t; while (t--)
#define TEST
const int N=2e5+10,M=1e3+10,mod=1e9+7;
int a[N],b[N],c[N],pre[N];
int dx[4]={0,1,0,-1};
int dy[4]={-1,0,1,0};
void solve(){
int n;
cin>>n;
vector<string>s(n);
for(int i=0;i<n;i++){
cin>>s[i];
}
queue<pair<int,int>>q;
auto check=[&](int x,int y)->bool{
if(s[x][y]=='1')return 0;
for(int i=0;i<4;i++){
int x1=x+dx[i],y1=y+dy[i];
int x2=x+dx[(i+1)%4],y2=y+dy[(i+1)%4];
if(x1<0|x1>=n||y1<0||y1>=n||x2<0||x2>=n||y2<0||y2>=n)continue;
if(s[x1][y1]=='1'&&s[x2][y2]=='1'){
return 1;
}
}
return 0;
};
vector<vector<int>>vis(n,vector<int>(n));
//对队列进行初始化
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(s[i][j]=='1')continue;
if(check(i,j)&&!vis[i][j]){
q.emplace(i,j);
vis[i][j]=1;
}
}
}//取出并且进行处理,然后再扩展到旁边相邻的。
while(q.size()>0){
auto [x,y]=q.front();
s[x][y]='1';
q.pop();
for(int i=0;i<4;i++){
int x1=x+dx[i],y1=y+dy[i];
if(x1<0||x1>=n||y1<0||y1>=n)continue;
if(check(x1,y1)&&!vis[x1][y1]){
q.emplace(x1,y1);
vis[x1][y1]=1;
}
}
}
for(int i=0;i<n;i++){
cout<<s[i]<<endl;
}
};
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
TESTS{
solve();
};
return 0;
}

浙公网安备 33010602011771号