Aug. 2023 普及组模拟赛 2
T1 地址
Meaning
给定一个字符串,判断是否合法。若不合法,则将其变为合法字符串。
Solution
情况较少,直接枚举每个字符判断。实现时应注意:
- 题目强调了数据保证字符串中存在且仅存在 \(4\) 个被字符分开的整数,也就是说,可以利用数的连续性缩小分支结构。
- 注意判断是否所有的
.都合法,放在最后不合法。
代码
#include<bits/stdc++.h>
using namespace std;
char a[100],ans[100];
int n,tem,cnt;
bool flag;
stack<int> st;
inline void pus(int x){
while(x%10!=x){
st.push(x%10);
x=x/10;
}
++cnt;
ans[cnt]=x+'0';
while(!st.empty()){
++cnt;
ans[cnt]=st.top()+'0';
st.pop();
}
}
int main(){
freopen("ip.in","r",stdin);
freopen("ip.out","w",stdout);
scanf("%s",a);
int n=strlen(a);
for(int i=0;i<n;++i){
if(a[i]>='0'&&a[i]<='9'){
if(a[i]=='0'&&(!tem)) flag=1;
while(a[i]>='0'&&a[i]<='9'){
tem=tem*10+a[i]-'0';
++i;
}
--i;
if(tem>255){
flag=1;
pus(255);
tem=0;
}else{
pus(tem);
tem=0;
}
++cnt;
ans[cnt]='.';
}else if(a[i]!='.'){
flag=1;
}
}
if(a[n-1]=='.') flag=1;
if(flag==1) printf("NO\n");
else return printf("YES\n"),0;
for(int i=1;i<cnt;++i) printf("%c",ans[i]);
return 0;
}
T2 内积
Meaning
给定两个数组,使两个不同数组数组中的元素相乘,求所有元素求积后积的最大和。
Solution
可以看作是一个数组表示一组值,另一个数组表示贡献。对于每个值,从贡献数组中匹配一个该值的贡献。可得对于越大的值,我们希望它做的贡献也越大。
可以将两个数组按相同的方式(同为升序或同为降序)排序,让两数组中同为第 \(k\) 大的数相乘求积之和。
代码
#include<bits/stdc++.h>
using namespace std;
long long n,a[2000000],b[2000000],ans;
int main(){
freopen("nj.in","r",stdin);
freopen("nj.out","w",stdout);
scanf("%lld",&n);
for(int i=0;i<n;++i) scanf("%lld",&a[i]);
for(int i=0;i<n;++i) scanf("%lld",&b[i]);
sort(a,a+n);
sort(b,b+n);
for(int i=0;i<n;++i) ans+=a[i]*b[i];
printf("%lld",ans);
return 0;
}
T3 翻转
Meaning
给定一个只含 \(0,1\) 的矩阵,每次可以改变一个位置和它上,下,左,右四个位置上的值,求是否可以使该矩阵上的所有值变为相同的数。若可以,则求出所需最小的改变次数。
Solution
数据范围很小,可以考虑深搜或枚举。
假设要把所有值变为 \(y\),且有
对于矩阵 \(a\),如果 \(a_{i,j}\ne{y}(i\ne{n})\),那么为了保证这一行的状态,使 \(a_{i,j+1}\leftarrow{\operatorname{opp}_{a_{i,j+1}}}\) 或 \(a_{i,j-1}\leftarrow{\operatorname{opp}_{a_{i,j-1}}}\) 会不断破环这一行的某个元素,就需要使 \(a_{i+1,j}\leftarrow{\operatorname{opp}_{a_{i+1,j}}}\)。以此类推,到最后一行时,如果还存在 \(a_{n,i}\ne{y}\) 则因继续改变 \(a_{n,i}\) 需要破坏上方状态而可以断定这种状态下不存在合法改变方式。
下图展示了一种情况: 
可以用深搜枚举第一列的状态,复杂度为 \(O(2^n)\),再进行上述操作,复杂度为 \(O(n^2)\)。
代码
#include<bits/stdc++.h>
using namespace std;
bool a[20][20],tem[20][20];
char ch;
int n,minn=0x3f3f3f3f,dir[2][5]={{0,0,0,1,-1},{0,1,-1,0,0}};
inline void flip(int x,int y){
for(int i=0;i<5;++i){
if(tem[x+dir[0][i]][y+dir[1][i]]==1) tem[x+dir[0][i]][y+dir[1][i]]=0;
else tem[x+dir[0][i]][y+dir[1][i]]=1;
}
}
inline void act(int* x,int y){
int step=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j) tem[i][j]=a[i][j];
}
for(int i=1;i<=n;++i){
if(tem[1][i]!=x[i]){
flip(1,i);
++step;
}
}
for(int i=1;i<n;++i){
for(int j=1;j<=n;++j){
if(tem[i][j]!=y){
++step;
flip(i+1,j);
}
}
}
for(int i=1;i<=n;++i) if(tem[n][i]!=y) return;
minn=min(minn,step);
}
inline void dfs(int* arr,int x,int y){
if(x>n){
act(arr,1);
act(arr,0);
return;
}
int *c=arr;
c[x]=y;
dfs(c,x+1,1);
dfs(c,x+1,0);
}
int main(){
freopen("fz.in","r",stdin);
freopen("fz.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
ch=getchar();
while(ch<'a'||ch>'z') ch=getchar();
if(ch=='b') a[i][j]=1;
else a[i][j]=0;
}
}
int b[20];
dfs(b,1,1);
dfs(b,1,0);
if(minn==0x3f3f3f3f) printf("Impossible");
else printf("%d",minn);
return 0;
}
T4 阶乘
Meaning
给定一个数 \(n\),求满足 \(\frac{a!}{b!}=n\) 的数对 \((a,b)\) 的个数。
Solution
枚举复杂度过高,需要优化。
由于 \(\frac{a!}{b!}=\begin{matrix} \prod_{i\in[a+1,b]} i \end{matrix}\),所以当 \(len=b-a\) 时,可得:
- \(a^{len}<n\),即 \(a<\sqrt[len]{n}\),因为当 \(i\in[a+1,b]\) 时,\(a<i\)。
- \(b^{len}\geq{n}\),即 \(b\geq\sqrt[len]{n}\),因为当 \(i\in[a+1,b]\) 时,\(b\geq{i}\)。
- \(1\leq{len}<20\),根据数据范围即可得到(\(10^{18}<20!\))。
我们可以根据以上结论直接优化枚举。
代码
#include<bits/stdc++.h>
using namespace std;
long long cases,n;
priority_queue<pair<long long,long long>,vector<pair<long long,long long> >,greater<pair<long long,long long> > > pq;
inline long long read(){
char ch=getchar();
long long x=0;
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
inline long long binpow(long long x,long long y){
long long ans=1;
while(y>0){
if(y&1==1) ans*=x;
x*=x,y>>=1;
}
return ans;
}
int main(){
freopen("jc.in","r",stdin);
freopen("jc.out","w",stdout);
cases=read();
while(cases--){
n=read();
if(n==1){
printf("-1\n");
continue;
}
pq.push({n,n-1});
for(long long l=2;l<20;++l){
for(long long i=powl(n,(double)1/l)-l;i<=powl(n,(double)1/l);++i){
if(i<=0) continue;
int j=i+l;
long long tem=1;
for(int k=i+1;k<=j;++k){
tem*=k;
if(tem>n) goto placea;
}
if(tem==n) pq.push({j,i});
placea:;
}
}
printf("%lld\n",pq.size());
while(!pq.empty()){
printf("%lld %lld\n",pq.top().first,pq.top().second);
pq.pop();
}
}
return 0;
}

浙公网安备 33010602011771号