2023.8.20 普及模拟2
这次又㕛叒叕垫底了。
哈哈哈,T1挂掉了,T3写崩了,T4暴力骗分。
T1
简化题意
判断一个 IP 地址是否合法(数据保证字符串中存在且仅存在4个被字符分开的整数),不合法时改正。
思路
简单模拟题,但我写挂了(没判断最后一位),学校数据甚至没有合法情况。
code
#include<bits/stdc++.h>
using namespace std;
char s[100],k[100];
int cnt;bool f;
signed main(void){
freopen("ip.in","r",stdin);
freopen("ip.out","w",stdout);
cin>>(s+1);
int n=strlen(s+1);
for(int lll=0,x=0,i=1;i<=n;++i){
if(s[i]>='0'&&s[i]<='9'){
if(s[i]=='0') ++lll;
x=(x<<1)+(x<<3)+(s[i]^48);
}
if((s[i]<'0'||s[i]>'9')||(i==n)){
if((s[i]!='.'&&i!=n)||(i==n&&s[i]<'0'||s[i]>'9')) f=1;
if(x||lll){
x=min(x,255);
if(x>225||lll>1) f=1;
int h[5]={0},pp=0;
if(!x) h[++pp]=0;
while(x){
h[++pp]=x%10;
x/=10;
}
for(int i=pp;i;--i)
k[++cnt]=h[i]+'0';
x=0,lll=0;
}
if(k[cnt]!='.') k[++cnt]='.';
}
}
if(f){
puts("NO");
for(int i=1;i<=cnt-1;++i)
cout<<k[i];
if(k[cnt]=='.') return 0;
else cout<<k[cnt];
}
else puts("YES");
return 0;
}
T2
简化题面
两个序列 \(A,B\)。可以任意交换序列里的元素位置。
使排列后 \(\sum\limits_{i=1}^n a_i \times b_i\) 最大。
思路
考虑贪心,使序列 \(A,B\) 均从小到大排序,在枚举出答案。
即如果 \(a_i < a_j,b_i<b_j\),则一定 \(a_i \times b_i + a_j \times b_j > a_i \times b_j + a_j \times b_i\)
证明:
\(\because a_i < a_j,b_i<b_j\)
\(\therefore a_j-a_i>0,b_j-b_i>0\)
故 \((a_j-a_i) \times (b_j-b_i) >0\)
展开的 \(a_j \times b_j+ai \times b_i-a_j \times b_i-a_i \times b_j > 0\)
移项得 \(a_i \times b_i + a_j \times b_j > a_i \times b_j + a_j \times b_i\)
证毕
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,ans,a[N],b[N];
inline bool cmp(int x,int y){
return x>y;
}
signed main(void){
freopen("nj.in","r",stdin);
freopen("nj.out","w",stdout);
scanf("%lld",&n);
for(int i=1;i<=n;++i){
scanf("%lld",a+i);
}
for(int i=1;i<=n;++i){
scanf("%lld",b+i);
}
sort(a+1,a+n+1);
sort(b+1,b+n+1);
for(int i=1;i<=n;++i){
ans+=a[i]*b[i];
}
printf("%lld\n",ans);
}
T3
思路
考场时用的是 洛谷原题P2040 的做法,只能跑过 \(n \le 4\) 的数据。
正解是开两个数组分别去存黑色和白色的情况,在一行一行的搜索,并判断是否符合。两种情况的答案取小。
code
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int dx[]={0,1,0,-1,0};
const int dy[]={0,0,1,0,-1};
int n,a[20][20],b[20][20];
int ans,ans1=inf,ans2=inf;
int vis1[20][20],vis2[20][20];
inline bool check1(int x,int y){
if(!x||!y) return 0;
int res=a[x][y];
for(int i=0;i<5;++i){
int xx=x+dx[i],yy=y+dy[i];
res+=vis1[xx][yy];
}
return res&1;
// return (a[x][y]+vis1[x][y]+vis1[x+1][y]+vis1[x-1][y]+vis1[x][y+1]+vis1[x][y-1])&1;
}
inline void dfs1(int x,int y,int tot){
if(tot>=ans1) return ;
if(y==n+1) y=1,++x;
if(x==n+1){
for(int i=1;i<=n;++i)
if(check1(n,i))
return ;
ans1=tot;
return ;
}
vis1[x][y]=0;
if(!check1(x-1,y)) dfs1(x,y+1,tot);
vis1[x][y]=1;
if(!check1(x-1,y)) dfs1(x,y+1,tot+1);
}
inline bool check2(int x,int y){
if(!x||!y) return 0;
int res=b[x][y];
for(int i=0;i<5;++i){
int xx=x+dx[i],yy=y+dy[i];
res+=vis2[xx][yy];
}
return res&1;
// return (b[x][y]+vis2[x][y]+vis2[x+1][y]+vis2[x-1][y]+vis2[x][y+1]+vis2[x][y-1])&1;
}
inline void dfs2(int x,int y,int tot){
if(tot>=ans1||tot>=ans2) return ;
if(y==n+1) y=1,++x;
if(x==n+1){
for(int i=1;i<=n;++i)
if(check2(n,i))//判断最后一行是否都翻上
return ;
ans2=tot;
return ;
}
vis2[x][y]=0;//vis:0:不翻 1:翻
//只有上一行的棋的状态为需要的状态,才会往下搜
if(!check2(x-1,y)) dfs2(x,y+1,tot);
vis2[x][y]=1;
if(!check2(x-1,y)) dfs2(x,y+1,tot+1);
}
signed main(void){
freopen("fz.in","r",stdin);
freopen("fz.out","w",stdout);
scanf("%d",&n);
char s;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
cin>>s;
if(s=='b') a[i][j]=1;
if(s=='w') b[i][j]=1;
}
}
dfs1(1,1,0);dfs2(1,1,0);
int ans=min(ans1,ans2);
if(ans==0x3f3f3f3f) puts("Impossible");
else printf("%d\n",ans);
return 0;
}
T4
简化题面
给定 \(n\) , 使得 \(n = \tfrac{a!}{b!}\) 。问有多少组 \(a,b\) 并输出每组 \(a,b\)。
思路
根据定义,\(n\) 其实就是把 \(a\) 到 \(b\) 之间的数字乘起来,乘法的增长速率是很大的,也就是说 \(a\) 和 \(b\) 的差值不会很大,很显然不超过 \(20\)。
所以可以枚举 \(c=a-b\),那么一定有 \(a^c \le n \le b^c\) .
这样的话 \(a\) 和 \(b\) 也是在一个很小的范围内,可以直接枚举了。
code
#include<bits/stdc++.h>
#define int __int128
using namespace std;
const int N=22;
int T,n,x,y,k,cnt,a[N],b[N];
inline int read(){
int x=0;bool f=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=1;s=getchar();}
while(s>='0'&&s<='9'){x=(x<<1)+(x<<3)+(s^48);s=getchar();}
return f?-x:x;
}
inline void write(int x){
if(x<0) x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
signed main(void){
freopen("jc.in","r",stdin);
freopen("jc.out","w",stdout);
T=read();
while(T--){
n=read();cnt=0;
if(!n||n==1){
puts("-1");
continue;
}
a[++cnt]=n;b[cnt]=n-1;
for(int i=2;i<=20;++i){
//a^d<=x<=b^d
x=pow(n,1.0/i);//a
while(1){
y=x-i+1;k=1;//b
for(int j=y;j<=x;++j) k*=j;
if(k>n) break;
if(k==n&&y!=1){
a[++cnt]=x;
b[cnt]=y-1;
}
++x;
}
}
write(cnt);putchar('\n');
for(int i=cnt;i;--i){
write(a[i]);putchar(' ');
write(b[i]);putchar('\n');
}
}
return 0;
}
总结
这次比赛,打到 9:30 就去干别的了,主要还是进度太垮了,T1因此报废,T4也只骗了10分。
哈哈哈,T1,T3题面上分别有要输出 Yes
和Impossible
。但学校数据点竟然都没有这种情况,真是吸取总司令的经验。