首页 > 其他分享 >2024初三年后集训模拟测试2

2024初三年后集训模拟测试2

时间:2024-02-20 09:24:31浏览次数:34  
标签:cnt 奇数 int dfrac else 2024 num 集训 模拟

前言

没什么好说的,丫的为啥不用开 \(freopen\) ,我全开了 qwq

很好的全部爆零,他题面里明明要求 \(freopen\) ,但是标准输入输出,没这个经验,长个见识吧就当。

去了 \(freopen\) 后:

image

  • \(T1\) 大模拟,不好打但肯调就能出。
  • 剩下的都不是很会,打到 \(T4\) 愣了半天题面就结束比赛了,\(T3\) 该死的捆绑测试,所以没骗来分。

\(\text{NOIP}\) 模拟赛,头一回做这种难度的,能做出来一道知足了。


T1 小P的2048

  • 题意:

    题面挺长的,里面有一些地方不太容易懂,多读几遍理解题意后就没那么难了。

    把图沾过来吧,方便解释:

    image

    1. 平移:

      他这个平移不是平移某一个棋子,是把整个棋盘的所有棋子都平移。

      以向上平移为例,就是把所有棋子向上挪直到全部顶到头,\(eg:\)

      image

    2. 合并:

      不能连续合并,却能同时合并多对,具体是什么意思?

      \(eg:\)

      image

  • 数据范围:

    \(2\leq n\leq 8\) ,随便跑就完事了,不用担心时间复杂度。

  • 解法:

    按照题意大模拟即可。

    原矩阵为 \(a_{i,j}\) ,定义新矩阵为 \(b_{i,j}\) ,用于存移动后的状况,移动完后另 \(a=b\) ,\(b\) 清空。

    • 处理平移与合并:

      直接看代码理解比较方便:

      1. 上移:

        if(x==0)
        {
            for(int j=1;j<=n;j++)
            {
                int cnt=0;//全部顶到头。
                for(int i=1;i<=n;i++)
                    if(a[i][j]!=0)
                    {
                        if(b[cnt][j]==a[i][j]&&num==0)//合并,不可连续合并。
                            b[cnt][j]+=a[i][j],
                            ans+=b[cnt][j],
                            num++;
                        else 
                        {
                            if(num>0) num=0;
                            b[++cnt][j]=a[i][j];
                        }
                    }
            }
        }
        
      2. 下移:

        else if(x==1)
        {
            for(int j=1;j<=n;j++)
            {
                int cnt=n+1;
                for(int i=n;i>=1;i--)
                    if(a[i][j]!=0)
                    {
                        if(b[cnt][j]==a[i][j]&&num==0)
                            b[cnt][j]+=a[i][j],
                            ans+=b[cnt][j],
                            num++;
                        else 
                        {
                            if(num>0) num=0;
                            b[--cnt][j]=a[i][j];
                        }
                    }
            }
        }
        
      3. 左移:

        else if(x==2)
        {
            for(int i=1;i<=n;i++)
            {
                int cnt=0;
                for(int j=1;j<=n;j++)
                    if(a[i][j]!=0)
                    {
                        if(b[i][cnt]==a[i][j]&&num==0)
                            b[i][cnt]+=a[i][j],
                            ans+=b[i][cnt],
                            num++;
                        else 
                        {
                            if(num>0) num=0;
                            b[i][++cnt]=a[i][j];
                        }
                    }
            }
        }
        
      4. 右移:

        else if(x==3)
        {
            for(int i=1;i<=n;i++)
            {
                int cnt=n+1;
                for(int j=n;j>=1;j--)
                    if(a[i][j]!=0)
                    {
                        if(b[i][cnt]==a[i][j]&&num==0)
                            b[i][cnt]+=a[i][j],
                            ans+=b[i][cnt],
                            num++;
                        else 
                        {
                            if(num>0) num=0;
                            b[i][--cnt]=a[i][j];
                        }
                    }
            }
        }
        
    • 处理新加的点:

      先一遍循环,处理出剩几个空点,按照题面定义 \(s=1+k\bmod sum\) ( \(k\) 见题面,为输入进来的)。

      再来一遍循环,到第 \(s\) 个为 \(0\) 的 \(a_{i,j}\) 改成 \(v\) 即可( \(v\) 也是输进来的)。

    • 处理何时结束:

      很简单,如果进行过第 \(i\) 遍时 \(a\) 和上一次没有任何变化,那第 \(i\) 次操作就是无用的,也就是共可以进行 \(i-1\) 步,输出,结束程序即可。

      具体只需要在将 \(b\) 复制到 \(a\) 前比较 \(a,b\) 数组即可。

  • 代码如下:

#include<bits/stdc++.h>
#define int long long 
#define endl '\n'
using namespace std;
const int N=10;
template<typename Tp> inline void read(Tp&x)
{
    x=0;register bool z=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
    for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    x=(z?x:~x+1);
}
int n,m,a[N][N],num,ans,sum,b[N][N];
signed main()
{
	#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    read(n),read(m);
    int x,y,z;
    for(int i=1;i<=2;i++)   
        read(x),read(y),read(z),
        a[x][y]=z;
    for(int t=1;t<=m;t++)
    {
        read(x),read(y),read(z);
        memset(b,0,sizeof(b));
        num=0;
        if(x==0)
        {
            for(int j=1;j<=n;j++)
            {
                int cnt=0;
                for(int i=1;i<=n;i++)
                    if(a[i][j]!=0)
                    {
                        if(b[cnt][j]==a[i][j]&&num==0)
                            b[cnt][j]+=a[i][j],
                            ans+=b[cnt][j],
                            num++;
                        else 
                        {
                            if(num>0) num=0;
                            b[++cnt][j]=a[i][j];
                        }
                    }
            }
        }
        else if(x==1)
        {
            for(int j=1;j<=n;j++)
            {
                int cnt=n+1;
                for(int i=n;i>=1;i--)
                    if(a[i][j]!=0)
                    {
                        if(b[cnt][j]==a[i][j]&&num==0)
                            b[cnt][j]+=a[i][j],
                            ans+=b[cnt][j],
                            num++;
                        else 
                        {
                            if(num>0) num=0;
                            b[--cnt][j]=a[i][j];
                        }
                    }
            }
        }
        else if(x==2)
        {
            for(int i=1;i<=n;i++)
            {
                int cnt=0;
                for(int j=1;j<=n;j++)
                    if(a[i][j]!=0)
                    {
                        if(b[i][cnt]==a[i][j]&&num==0)
                            b[i][cnt]+=a[i][j],
                            ans+=b[i][cnt],
                            num++;
                        else 
                        {
                            if(num>0) num=0;
                            b[i][++cnt]=a[i][j];
                        }
                    }
            }
        }
        else if(x==3)
        {
            for(int i=1;i<=n;i++)
            {
                int cnt=n+1;
                for(int j=n;j>=1;j--)
                    if(a[i][j]!=0)
                    {
                        if(b[i][cnt]==a[i][j]&&num==0)
                            b[i][cnt]+=a[i][j],
                            ans+=b[i][cnt],
                            num++;
                        else 
                        {
                            if(num>0) num=0;
                            b[i][--cnt]=a[i][j];
                        }
                    }
            }
        }
        bool flag=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(a[i][j]!=b[i][j])
                {
                    flag=1;
                    break;
                }
        if(!flag) cout<<t-1<<endl<<ans,exit(0);
        flag=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(a[i][j]!=0)
                {
                    flag=1;
                    break;
                }
        if(!flag) cout<<t-1<<endl<<ans,exit(0);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                a[i][j]=b[i][j];
        sum=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(a[i][j]==0)
                    sum++;
        int s=1+(y%sum);
        sum=0;
        for(int i=1;i<=n;i++)   
            for(int j=1;j<=n;j++)
            {
                if(a[i][j]==0) 
                {
                    sum++;
                    if(sum==s) 
                    {
                        a[i][j]=z;
                        break;
                    }
                }
            }
    }
    cout<<m<<endl<<ans;
}

T2 子集

  • 题意:

    给定两正整数 \(n,k\) 且 \(k|n\) 。

    已知集合为 \(1\sim n\) ,求出 \(k\) 个互无交集的子集,且子集内元素和均相等。

  • 解法:

    打表

    设 \(m=\dfrac{n}{k}\) ,表示每个子集中元素的数量。

    • 判无解:

      1. 首先如果 \(n\neq 1,k=n\) ,则一定无解,很显然。

      2. 若 \(n\) 为偶数,且 \(m\) 为奇数,则无解:

        ∵ \(n|m\) ,\(n\) 为偶数,\(m\) 为奇数;设 \(n=2a\times (2b+1)\) 。\(2a=k,2b+1=m\) .

        则 \(\sum\limits_{i=1}^ni=\dfrac{(n+1)n}{2}=\dfrac{[2a(2b+1)+1]\times 2a(2b+1)}{2}\) 。

        则平均到 \(2a\) 个子集,每个子集元素和为 \(\dfrac{[2a(2b+1)+1]\times 2a(2b+1)}{2\times 2a}=a(2b+1)^2+\dfrac{2b+1}{2}\) ,显然这个数不是整数,所以无解。

    • 简单——\(m\) 为偶数:

      显然输出一个 \(i\) ,一个 \(n-i+1\) 就行了,部分分就是这么来的。

    • 难点——\(n,m\) 均为奇数:

      极其巧妙的做法:先按照上面方式搞,直到每一组剩下 \(3\) 个元素未填。

      接下来的问题就转换成如何排这 \(m=3\) 的情况。

      以 \(n=15,k=5\) 为例:

      image

      1. 先将最大的 \(k\) 个分别按从大到小顺序排到每一组,因为不会存在这 \(k\) 个中有 \(2\) 个在同一组。(排序是为了方便)。

      2. 根据公式 \(\dfrac{(n+1)n}{2k}\) 求出每个子集元素和 \(sum\) ,那么此时求出放完第一列后,每一组还需要多少,记作 \(val_i\) ,设 \(val_i=a_i+b_i\) ,分别表示 \(2,3\) 列。

      3. 接下来的步骤就变成了如何用剩下两列凑出每个 \(val_i\) ,此处需要分类讨论(接下来思路不易推出,可以结合上面的图):

        • \(i\) 为奇数:

          为什么要分类讨论呢?

          显然的,\(val_{i+1}-val_i=1\) ,∴ \(val_{i+2}-val_i=2\) ,这样的话就可以使 \(a_{i+2}-a_i=1,b_{i+2}-b_i=1\) 。这样的话 \(a,b\) 分别从 \(1,val_1-1\) 开始递增即可,参考上图。

        • \(i\) 为偶数:

          和上面一样的,但从剩下的数中选,\(a,b\) 从 \(\dfrac{n+3}{2},val_2-(\dfrac{n+3}{2})\) 递增即可,参考上图。

          具体为什么是从 \(\dfrac{n+3}{2}\) 开始,∵ \(n,k\) 均为奇数,那么 \(i\) 为奇数的情况用去了 \(1\sim \dfrac{n+1}{2}\) ,所以到偶数就从 \(\dfrac{n+3}{2}\) 开始轮了。

      好了现在规律找出来了,怎么输出还是个问题。

      所以就需要将上面的规律转化为能用 \(i,k\) 表示的公式,依旧是分类讨论,按照上面的思路来:

      • \(i\) 为奇数:

        1. 输出第一列:\(3k-i+1\) ,在这里 \(3k\) 就是上面 \(n\) 的意思了。
        2. 输出第二列:\(\dfrac{i+1}{2}\) 。
        3. 输出第三列:\(\dfrac{3k+i}{2}\) 。
      • \(i\) 为偶数:

        1. 输出第一列:\(3k-i+1\) ,和上面一样的。
        2. 输出第二列:\(\dfrac{k+i+1}{2}\) 。
        3. 输出第三列:\(\dfrac{2k+i}{2}\) 。

      这里需要解释一下:

      首先在第一列的数为 \(2k+1\sim 3k\) ,第二列为 \(1\sim k\) ,第三列为 \(k+1\sim 2k\) 。

      参照上面的思路与图片,不难发现第二列是 \(i\) 为奇数优先,而第三列是 \(i\) 为偶数优先。

      • 在第二列时:

        奇数优先从 \(1\sim\dfrac{k+1}{2}\) 中选,则转化为 \(i\) 就是 \(\dfrac{i+1}{2}\) 。

        而偶数则是在 \(\dfrac{k+3}{2}\sim k\) 中选,原本按奇数那个来就是 \(\dfrac{i}{2}\) ,但是每一个都对应加上 \(\dfrac{k+1}{2}\) ,就变为 \(\dfrac{k+i+1}{2}\) 。

      • 在第三列时:

        偶数优先从 \(k+1\sim \dfrac{3k-1}{2}\) 中选,则转化为 \(i\) 就是 \(k+\dfrac{i}{2}=\dfrac{2k+i}{2}\) 。

        而奇数则是在 \(\dfrac{3k+1}{2}\sim 2k\) 中选,若按偶数那个来就是 \(\dfrac{i+1}{2}\) ,单是每一个都加上 \(\dfrac{3k-1}{2}\) ,就变为 \(\dfrac{3k+i}{2}\) 。

      • 最后证明:

        由于 \(n,m,k\) 均为奇数,所以 \(i\) 为奇数的情况占 \(\dfrac{k+1}{2}\) ,而 \(i\) 为偶数的情况占 \(\dfrac{k-1}{2}\) ,上面奇偶分别所选范围就是这么来的。

      只需要先把这三列先输出,剩下的按照 \(m\) 为偶数那么来就可以了,当然这两部也可以调换,不过会稍微麻烦一点点,需要找到这三列里第一个数 \(s\) ,把上面的公式都加上 \(s-1\) 即可;若不换就直接用上面公式。

  • 代码如下:

#include<bits/stdc++.h>
#define int long long 
#define endl '\n'
using namespace std;
const int N=10;
template<typename Tp> inline void read(Tp&x)
{
    x=0;register bool z=1;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
    for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    x=(z?x:~x+1);
}
int t,n,m,k;
signed main()
{
	#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    read(t);
    while(t--)
    {
        read(n),read(k);
        
        int m=n/k;
        if((n%2==0&&m&1)||(m==1&&n!=1)) 
        {
            cout<<"No"<<endl;
            continue;
        }
        cout<<"Yes"<<endl;
        if(k==1)
        {
            for(int i=1;i<=n;i++) cout<<i<<' ';
            cout<<endl;
            continue;
        }
        if(m%2==0) 
        {
            int cnt=0;
            for(int i=1;i<=k;i++)
            {
                for(int j=1;j<=m/2;j++)
                    cout<<++cnt<<' '<<n-cnt+1<<' ';
                cout<<endl;
            }   
        }
        else 
        {
            int cnt=0,s=(n-k)/2-k+1;
            for(int i=1;i<=k;i++)
            {
                for(int j=1;j<=(m-3)/2;j++)
                    cout<<++cnt<<' '<<n-cnt+1<<' ';
                cout<<3*k+s-i<<' ';
                if(i&1) cout<<s+(i-1)/2<<' '<<s+k-1+(k+i)/2<<endl;
                else cout<<s+(k-1)/2+i/2<<' '<<s+k-1+i/2<<endl;//就是上面的公式加上 s-1 。
            }
        }
    }
}

标签:cnt,奇数,int,dfrac,else,2024,num,集训,模拟
From: https://www.cnblogs.com/Charlieljk/p/18021813

相关文章

  • 2024年,提升Windows开发和使用体验的实践经验 - RIME输入法
    前言上一篇文章介绍了Windows下的包管理器,本文继续介绍输入法。事实上Windows的输入法生态比Linux/Mac丰富很多,不过很多国产输入法存在窃取隐私、植入广告、乱安装流氓软件等问题,现在有开源的RIME输入法可以选择,何必受这气呢......
  • USACO Feb 2024 bronze
    挖个坑,今天晚上完成三篇手工翻译。awaT1PalindromeGame赛时100分经典博弈论。手动枚举一下,很容易发现规律,当S为10的倍数时,先手输。手动枚举需注意,不会证明你先别急,枚举要多,才能得出普遍规律(这个傻逼比赛刚开始一直打的是,当S为时10先手输)。需要注意的是S的非常......
  • 2024年,提升Windows开发和使用体验的一些实践 - 包管理器篇
    前言短暂的春节假期转瞬即逝,忙碌的一年又要开启了......
  • .NET周刊【2月第2期 2024-02-11】
    国内文章C#/.NET该如何自学入门?https://www.cnblogs.com/Can-daydayup/p/18006914随着DotNetGuide技术社区交流群的扩大,很多新成员希望知道如何自学C#/.NET。本文提出了自学建议:首先要了解语言特点与发展,然后制定详细学习计划,以微软官方文档为学习起点,并结合动手实践与其他资源......
  • 2024.2.19 在愿望的最后一个季节 记起我曾身藏利刃
    今天模拟赛,顺利过了T1然后发现T2是答辩题,T3写了送的。出分发现T2挂了,看起来是被T2卡哈希了,魔怔。下午讲的题都挺好的,晚上看了RMR,小蜜蜂乱杀,雪碧乱杀,就连C9都乱杀了,这才是我想象中的一线强队暴打二线队啊,不要学Faze和NAVI。子序列这个做法比较神秘。考虑试填,发......
  • 20240217
    创建拥有多的页面的单Activity应用,使用Jetpack的导航和其他组件1.介绍在这个记账本App中,我们不仅需要一个页面来记录支出和收入,还需要一个页面来显示支出和收入的统计信息。当然我们可以使用两个Activity来实现这个功能,但是Google更推荐的方式是使用单Activity多Fragment的架构......
  • 数学专题集训笔记
    感谢lsy学长来101给我们上课~Day1逆元对于一个\(a\),当\(ab\equiv1\pmod{m}\)时我们把\(b\)的最小整数解称作\(a\)模\(m\)的逆元,记作\(a^{-1}\)或\(\frac{1}{a}\)。接下来我们来看看逆元的求法。费尔马小定理如果\(a\)是一个整数,\(p\)是一个质数,则有\[a^p\e......
  • 2024初三集训模拟测试2
    2024初三集训模拟测试2\(T0\)谜之阶乘\(100pts\)详见普及模拟2T4阶乘。\(T1\)小P的2048\(10pts\)大模拟,没什么好说的。注意可以同时合并多对数字,但不能连续合并。点击查看代码lla[10][10];queue<ll>q;intmain(){ lln,m,x1,y1,v1,x2,y2,v2,d,k,v,su......
  • 2024牛客寒假算法基础集训营4 K.方块掉落
    线段树维护的信息有当前行有多少方块,一共有多少方块拿线段树维护一个矩阵就行,转移更新就是矩阵乘类似题有这个 牛客多校第二场-H-zhujio两题都基本上就是转移矩阵求出来正常建线段树,pushup就是直接矩阵乘 #include<bits/stdc++.h>usingnamespacestd;#defineen......
  • 2024程序员能有什么新的出路?
    前言前两天和一个前端同学聊天,他说不准备再做前端了,准备去考公。不过难度也很大。从20152016年那会儿开始互联网行业爆发,到现在有7、8年了,当年20多岁的小伙子们,现在也都30+了大量的人面临这个问题:大龄程序员就业竞争力差,未来该如何安身立命?先说我个人的看法:除非你......