8.19普及模拟二

image
就不该打那b表

\(\large{T1\ 地址} \ \ \tiny{100 pts}\)

  • 去年csp-jT3阉割版(sbDragen:这哪是阉割啊 这是连腰子都噶了)
  • 模拟就完了(又调半天给我去年T3 PTST整出来了)
#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
#define frer freopen("ip.in","r",stdin);
#define frew freopen("ip.out","w",stdout);
using namespace std;
string c;
int i=1,cnt;
int wr,num1,num2,num3,num4;

inline void works(int mod){
    int fir=0;
    while(c[i]>='0'&&c[i]<='9'){
        if(fir==0&&c[i]=='0'){
            wr=1;
        }
        if(fir==0&&c[i]!='0'){
            fir=1;
        }
        if(mod==1)num1=num1*10+(c[i]-'0');
        else if(mod==2)num2=num2*10+(c[i]-'0');
        else if(mod==3)num3=num3*10+(c[i]-'0');
        else if(mod==4)num4=num4*10+(c[i]-'0');
        i++;
        //cout << 1;
    }
    i--;
    // cout << c << " ";
    // cout << i<<" ";
    if(i!=c.size()-1&&(c[i+1]!='.'||(c[i+2]<'0'||c[i+2]>'9'))){
            wr=1;
    }
    while(i!=c.size()-1&&(c[i+1]<'0'||c[i+1]>'9')){
        i++;
    }
    i++;
}
inline void work(){
    works(1);
    works(2);
    works(3);
    works(4);
    if(num1>255){wr=1;num1=255;}
    if(num2>255){wr=1;num2=255;}
    if(num3>255){wr=1;num3=255;}
    if(num4>255){wr=1;num4=255;}
    if(wr){
       printf("NO\n"); 
       printf("%lld.%lld.%lld.%lld",num1,num2,num3,num4);
    } 
    else printf("YES\n");
}
signed main(){
    frer;
    frew;
    cin >> c;
    c=" "+c;
    work();
    //printf("%s",c);
    
    return 0;
}

\(\large{T2\ 内积} \ \ \tiny{100 pts}\)

  • 给定两个数组 \(a,b\),使\(\sum_{i=1}^{n}{a_i \times b_i}\)最大
  • 显然题,贪心
#include <iostream>
#include <cstdio>
#include <algorithm>
#define int long long
#define frer freopen("nj.in","r",stdin);
#define frew freopen("nj.out","w",stdout);
using namespace std;
const int Max = 1e6+10;
int n,ans;
int a[Max],b[Max];
inline int read(){
    int num=0,fl=1;char c=getchar();
    while(c <'0'||c >'9'){
        if(c=='-') fl=-1;
        c=getchar();
    }
    while(c >='0'&&c <= '9'){
        num=(num<<3)+(num<<1)+(c^48);
        c=getchar();
    }
    return fl*num;
}
signed main(){
     frer;
     frew;
     n=read();
    
    for(int i = 1;i <= n;i++){
        a[i]=read();
    }
    
    for(int i = 1;i <= n;i++){
        b[i]=read();
    }
    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",ans);
    return 0;
}

\(\large{T3\ 翻转} \ \ \tiny{10 pts}\)

  • 题意:给定一个由1和0组成的\(n\times n\)的矩形,每次可以将一个点和其上下左右四个点一同翻转。求使矩形全部为1或全部为0的最小翻转次数。
  • 因为当第一行的状态确定时,其他行的状态也可以确定(每行补上一行的空),最后一行因为没有下一行所以不能确定。所以只需枚举第一行的状态,在将其他行推出来,最后检查一遍最后一行是不是全部为目标状态即可(1或0)
    • 因为需要对矩形进行修改,所以需要另开一个数组进行备份。当每一次开始check时需要备份一下当期状态,check结束时还原,使dfs继续枚举下一种状态(不然之前的状态会丢失(?))
#include <iostream>
#include <cstring>
#define int long long
#define frer freopen("in.in","r",stdin);
#define frew freopen("out.out","w",stdout);
using namespace std;
const int Max = 20;
int n;
int map[Max][Max];
int mapp[Max][Max];
string s;
int ans = 0x3f3f3f3f3f3f;
inline int read(){
    int num=0,fl=1;char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') fl=-1;
        c=getchar();
    }
    while(c >='0'&&c <='9'){
        num=(num<<3)+(num<<1)+(c^48);
        c=getchar();
    }
    return num*fl;
}
inline void reMake1(){
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= n;j++){
            map[i][j]=mapp[i][j];
        }
    }
}
inline void reMake2(){
    for(int i = 1;i <= n;i++){
        for(int j = 1;j <= n;j++){
            mapp[i][j]=map[i][j];
        }
    }
}
inline void fz(int x,int y){
    map[x][y]^=1;map[x-1][y]^=1;map[x+1][y]^=1;map[x][y-1]^=1;map[x][y+1]^=1;
}
inline void check(int sum,int colr){
    reMake2();
    for(int i = 2;i <= n;i++){
        for(int j=1;j <= n;j++){
            if(map[i-1][j]!=colr){
                fz(i,j);
                sum++;
            }
        }
    }
    for(int i = 1;i <= n;i++)
        if(map[n][i]!=colr) 
            return;

    ans=min(ans,sum);
    return;
}
inline void dfs(int step,int sum,int colr){
    if(step==n){
        check(sum,colr);
        reMake1();
        return;
    }
    dfs(step+1,sum,colr);
    fz(1,step+1),dfs(step+1,sum+1,colr),fz(1,step+1);
}
signed main(){
    frer;
    frew;
    n=read();
    for(int i = 1;i <= n;i++){
        cin>>s;
        s=" "+s; 
        for(int j = 1;j <= n;j++){
            if(s[j]=='b') mapp[i][j]=1;
            else mapp[i][j]=0;
        }
    }
    reMake1();
    dfs(0,0,1);
    dfs(0,0,0);
    if(ans!=0x3f3f3f3f3f3f)printf("%lld",ans);
    else printf("Impossible");
    return 0;  
}

\(\large{T4\ 阶乘} \ \ \tiny{0 pts}\)

  • 题意:给定一个整数\(n\)\(a,b\in Z\),求使\(\dfrac{a!}{b!}=n\)的所有方案
  • 没思路,打了个表,本来可以拿10pts的,加了个1~100000所有质数的表结果C
    了TAT
  • 分析题目,可以将题目转化为求积为\(n\)的几个连续整数。我们就可以枚举\(a-b\)的长度,因为阶乘的增长速度很大,所以不会枚举很多,到21即可(21! 几乎可以覆盖所有整形)。
  • 假设 \(a_1*a_2*a_3*a_4*a_5=n(a_1,a_2,a_3,a_4,a_5为连续的五个整数) 可以得出 a_1\thickapprox \sqrt[5]{n}(a_2 - a_5同理)\) 那么假设 \(len=a-b\), 显然可以得出 \(a\geq\sqrt[len]{n},b\leq\sqrt[len]{n}\)
  • 我们就可以枚举区间长度,令\(r=\sqrt[len]{n}\)(\(r\)的最小值),\(l=r-len+1\) 并不断调整区间位置,直至积等于\(n\)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#define int long long
#define frer freopen("in.in","r",stdin);
#define frew freopen("out.out","w",stdout);
using namespace std;
const int Max = 1e6;
int T;
int n,sum,cnt;
struct node{
    int a,b;
}ans[Max];
inline int read(){
    int num=0,fl=1;char c=getchar();
    while(c <'0'||c >'9'){
        if(c=='-') fl=-1;
        c=getchar();
    }
    while(c >='0'&&c <= '9'){
        num=(num<<3)+(num<<1)+(c^48);
        c=getchar();
    }
    return fl*num;
}
signed main(){
    frer;
    frew;
    T=read();
    while(T--){
        cnt=0;
        n=read();
        if(n==1){
            printf("-1\n");
            continue;
        }
        for(int len = 2;len <= 21;len++){
            for(int r= pow((double)(n),1.0/(double)(len));;r++){
                int l=r-len+1;
                sum=1;
                for(int i = l;i <= r;i++) sum*=i;
            
                if(sum>n) break;

                if(sum==n&&l-1!=0){
                    ans[++cnt]=(node){r,l-1};
                }
               
            }
        }
        printf("%lld\n",cnt+1);
        for(int i = cnt;i >= 1;i--){
            printf("%lld %lld\n",ans[i].a,ans[i].b);
        }
        printf("%lld %lld\n",n,n-1);
    }
    return 0;
}

$\large{总结} $

少整点没用的
有点思维含量的题就挂

posted @ 2023-08-19 21:47  tkt  阅读(16)  评论(2编辑  收藏  举报