2023.8.20 普及模拟2

这次又㕛叒叕垫底了。

image

哈哈哈,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

洛谷原题P1764

思路

考场时用的是 洛谷原题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题面上分别有要输出 YesImpossible。但学校数据点竟然都没有这种情况,真是吸取总司令的经验。

posted @ 2023-08-20 09:43  GOD_HJ  阅读(40)  评论(0编辑  收藏  举报