一.闲话

太菜了,又被各位神仙吊打qwq

二.题解

A.L1-1 I LOVE WIT

签到题,没啥技巧,模拟即可~
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string x="I LOVE WIT";
    int len=x.size();
    for(int i=0;i<len;++i){
        for(int j=1;j<=i;++j){
            putchar(' ');
        }
        cout<<x[i]<<'\n';
    }
    return 0;
}

B.L1-2 单位换算

由题,直接输出即可,若答案为整数输直接输出,否则保留小数

有个小技巧,我们可以直接用double存答案,然后比较下double的值与double转int后的值即可判断是否为整数

代码:

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-3;
int main(){
    int n;
    scanf("%d",&n);
    double res=1.0*n*12*25.4;
    int ret=res;
    if(fabs(ret-res)<=eps){
        printf("%d",ret);
    }else{
        printf("%.1lf",res);
    }
    return 0;
}

C.L1-3 Pokémon

又是签到题,若f=1,输出,否则输出

烦的地方主要是输入带%,小技巧就是,先把值输入进double里面,再输入一个char,就可以无视%了

代码:

#include<bits/stdc++.h>
using namespace std;
double p[7];
int main(){
    char s;
    for(int i=0;i<=6;++i){
        cin>>p[i]>>s;
    }
    int tp,opt;
    cin>>tp>>opt;
    if(opt==1){
        p[tp]*=0.01;
    }else{
        p[tp]*=0.99;
    }
    printf("%.2lf",p[tp]);putchar('%');
    return 0;
}

D.L1-4 颠倒阴阳

模拟即可,需要注意的是,题目要求的是从从左到右第一个为1的位置到最低位(就是最后那个2^0的位置)反转。。。题目有点不明确,多试几次就行了

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main(){
    int n;
    scanf("%lld",&n);
    if(n==0){
        puts("0");
        return 0;
    }
    int l=0,r=0;
    for(int i=0;i<=31;++i){
        if((n>>i)&1){
            l=min(l,i),r=max(r,i);
        }
    }
    for(int i=l;i<=r;++i){
        n^=(1<<i);
    }
    int ans=0;
    for(int i=31;~i;--i){
        if((n>>i)&1){
            ans+=(1LL<<(31-i));
        }
    }
    printf("%lld",ans);
    return 0;
}

E.L1-5 演唱会

直接算可能有点麻烦(真的只有一点),我们可以考虑把所有单位化为相同的,这样就好比较了,为了避免精度问题,我直接把所有时间换算成秒,这样就可以直接比较大小了
代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int h,m,s;
    char ss;
    cin>>h>>ss>>m>>ss>>s;
    int tot=h*3600+m*60+s;
    tot+=3600+22*60+33;
    int al=19*3600,ed=21*3600;
    if(tot<al){
        puts("arrive on time");
    }else if(tot<ed){
        puts("arrive late");
    }else{
        puts("too late");
    }
    return 0;
}

F.L1-6 分鸽子

一道标准的二分题(貌似就是一种版本的小木棍那题?)

读题可以发现,答案明显满足二分性,所以我们二分答案,然后算出最多可以分出多少分鸽子肉(看出出题人对鸽子的愤怒了/x),把这个值和m比较一下就行了

代码:

#include<bits/stdc++.h>
using namespace std;
int w[100001];int n,m;
inline bool check(int x){
    int res=0;
    for(int i=1;i<=n;++i){
        res+=(w[i]/x);
    }
    return res>=m;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&w[i]);
    }
    int l=1,r=1e9,ans=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)){
            ans=mid,l=mid+1;
        }else{
            r=mid-1;
        }
    }
    printf("%d",ans);
    return 0;
}

G.L1-7 拼接梯子

一道结论题,类比二进制拆分即可,(注意没有2^0)

我们从大到小枚举能分则分,最后看剩余的值是否为0即可

代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
    long long k,n;
    cin>>k>>n;
    long long ans1=1;
    for(int i=k;i;--i){
        if((n>>i)&1){
            n-=(1LL<<i);
            ans1=max(ans1,(1LL<<i));
        }
    }
    if(!n){
        puts("Yes");
        printf("%lld",ans1);
    }else{
        puts("No");
    }
    return 0;
}

H. L1-8 幻想乡炼金学

发现是个码农模拟题,emmmm反正也没啥知识点,打的又麻烦就不填坑辣!(qwq)

I. L2-1 特殊的沉重球

由于是15点50多才开始打比赛,所以做到这题时只有10多分钟了qwq,草草打了个dfs,居然出锅了!(我:???)

于是,考场中就没做出来,后面debug发现是个sb错误(新建一组时没把当前的值加进去),然后改了下70points,怎么办呢?

卡时优化天下第一!

然后。。。就A了,2333
(dfs怎么打应该不用说吧?)

一个小技巧,因为我们装精灵的顺序对背包剩余空间没有影响,所以我们可以规定每个背包优先装编号小的,这样可以加速不少时间(简单来说就是枚举组合而不是排列)

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=21,T=10000000;//卡时常数
int c[N];int n,w,ans;
int tp[N],po=T;
inline void dfs(int now,int res){
    if(res>=ans){
        --po;
        if(!po){
            printf("%d",ans);
            exit(0);
        }
        return;
    }
    if(now==n+1){
        ans=res;
        return;
    }
    for(int i=1;i<=res;++i){
        if(tp[i]+c[now]<=w){
            tp[i]+=c[now];
            dfs(now+1,res);
            tp[i]-=c[now];
        }
    }
    tp[res+1]=c[now];
    dfs(now+1,res+1);
}
int main(){
    ans=2e9;
    scanf("%d%d",&n,&w);
    for(int i=1;i<=n;++i){
        scanf("%d",&c[i]);
    }
    dfs(1,0);
    printf("%d",ans);
    return 0;
}

J.L2-2 又见火车入栈

直接做的话可能不太好做,但是,我们可以将询问离线下来做,这样,我们把询问按x排序后,就可以直接动态模拟入栈出栈的过程同时更新答案了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
struct node{
    int x,y,w;
}t[N];
int ans[N];
int sta[N],top;
bool opt[N];
inline bool kkk(node x,node y){
    return x.x<y.x;
}
int main(){
    int n;
    scanf("%d",&n);
    char ss[4];
    for(int i=1;i<=n;++i){
        scanf("%s",ss);
        opt[i]=(ss[0]=='i');
    }
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;++i){
        scanf("%d%d",&t[i].x,&t[i].y);
        t[i].w=i;
    }
    sort(t+1,t+q+1,kkk);
    int now=1,cnt=0;
    for(int i=1;i<=n;++i){
        if(opt[i]){
            sta[++top]=++cnt;
        }else{
            --top;
        }
        while(now<=q&&t[now].x==i){
            ans[t[now].w]=sta[t[now].y];
            ++now;
        }
        if(now==q+1){
            break;
        }
    }
    for(int i=1;i<=q;++i){
        printf("%d\n",ans[i]);
    }
    return 0;
}

K. L2-3 新旷野地带

简单数论题,相当于棋盘放车,假设我们在棋盘中放i个"车",那么方案数如下:

我们先从n行中选i行放车,再从j列中选i列放车,这样每行每列一定最多只有一个车,然后把这个i个列分别分配个i个行,进行组合,分配方式有i!种,所以方案数就是
直接预处理组合数和阶乘即可O(1)计算贡献,O(n)枚举i即可

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7,N=1e6+1;
int C1[N],C2[N],f[N],g[N];
int main(){
    f[0]=f[1]=g[0]=g[1]=1;
    for(int i=2;i<N;++i){
        f[i]=(1LL*f[i-1]*i)%mod;
        g[i]=(1LL*g[mod%i]*(mod-mod/i))%mod;
    }
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    C1[1]=n,C2[1]=m;
    for(int i=2;i<=k;++i){
        C1[i]=(1LL*C1[i-1]*(n-i+1))%mod;
        C1[i]=(1LL*C1[i]*g[i])%mod;
        C2[i]=(1LL*C2[i-1]*(m-i+1))%mod;
        C2[i]=(1LL*C2[i]*g[i])%mod;
    }
    k=min(k,min(n,m));
    int ans=0;
    for(int i=1;i<=k;++i){//枚举放几个
        //选i行放,选i列放,然后每行放的顺序乱序
        //ans+=C i,n*C i.m*i!
        ans+=(1LL*((1LL*C1[i]*C2[i])%mod)*f[i])%mod;
        ans%=mod;
    }
    printf("%d",ans);
    return 0;
}

L.2-4 缘之空

简单的lca模板,但需要注意的是,题目并没有说根节点为1(这也是坑点所在),但是题目明确了每个点的父亲,所以,我们只要找到没有被指定父亲的那个节点,那个节点就是根,其他的就是个lca模板了。。。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+1;
struct node{
    int v,nex;
}t[N<<1];
int fa[N][18];
int dep[N];
int len,las[N];
bool is_not_fa[N];
inline void add(int u,int v){
    t[++len]=(node){v,las[u]},las[u]=len;
}
inline void dfs(int now){
    for(int i=1;i<=17;++i){
        fa[now][i]=fa[fa[now][i-1]][i-1];
    }
    for(int i=las[now];i;i=t[i].nex){
        int v=t[i].v;
        dep[v]=dep[now]+1;fa[v][0]=now;
        dfs(v);
    }
}
inline int lca(int x,int y){
    if(dep[x]>dep[y]){
        x^=y^=x^=y;
    }
    int cha=dep[y]-dep[x];
    for(int i=17;~i;--i){
        if(cha>=(1<<i)){
            cha-=(1<<i);
            y=fa[y][i];
        }
    }
    if(x==y){
        return x;
    }
    for(int i=17;~i;--i){
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i],y=fa[y][i];
        }
    }
    return fa[x][0];
}
int main(){
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<n;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);is_not_fa[v]=1;
    }
    int rt;
    for(int i=1;i<=n;++i){
        if(!is_not_fa[i]){
            rt=i;
        }
    }
    dep[rt]=1;
    dfs(rt);
    while(q--){
        int u,v;
        scanf("%d%d",&u,&v);
        int x=lca(u,v);
        int dis=dep[u]+dep[v]-2*dep[x];
        if(dis<=4||x==u||x==v){
            puts("NO");
        }else{
            puts("YES");
        }
        printf("%d\n",dis);
    }
    return 0;
}