2023“钉耙编程”中国大学生算法设计超级联赛(3)

2023-11-10

Chaos Begin 贪心/凸包

Out of Control DP,递推

Operation Hope 贪心/2-sat与二分

8-bit Zoom 二维前缀

Noblesse Code 轨迹哈希,字典序,差分

 Problem - 7303

 

2n个点,分为两组,使得第一组整体偏移相同方向和距离能够得到第二组。

考虑,对x降序排序,x相同则y降序排序。然后固定第一个点为第一个集合。暴力枚举与之配对的第二集合的一点,获得dx,dy。然后贪心的去匹配。如果当前点没有被用到,因为dx一定大于等于0,故当前点只能是第一集合点,再以此为标准移动,dx,dy看是否有与之配对点。如果没有,则退出。

而至于题解的“凸包”写法,过于小题大做。

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
pair<int,int>a[500000+10];
map<pair<ll,ll>,int>mp,cnt;
int main()
{
    cin>>t;
    while(t--)
    {
        int n;
        scanf("%d",&n);
        mp.clear();
        cnt.clear();
        for(int i=1; i<=2*n; i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            a[i].first=x;
            a[i].second=y;
            cnt[a[i]]++;
        }
        sort(a+1,a+1+2*n);
        set<pair<int,int>>ans;
        for(int i=2; i<=2*n; i++)
        {
            int dx=a[i].first-a[1].first;
            int dy=a[i].second-a[1].second;
            mp.clear();
            int temp=0;
            for(int j=1; j<=2*n; j++)
            {
                if(mp[a[j]]==cnt[a[j]])
                    continue;
                mp[a[j]]++;
                if(mp[make_pair(a[j].first+dx,a[j].second+dy)]<cnt[make_pair(a[j].first+dx,a[j].second+dy)])
                {
                    mp[make_pair(a[j].first+dx,a[j].second+dy)]++;
                    temp++;
                }
                else
                {
                    break;
                }
            }
            if(temp==n)
            {
                ans.insert(make_pair(dx,dy));
                if(dx==0&&dy==0)
                    continue;
                ans.insert(make_pair(-dx,-dy));
            }
        }
        cout<<ans.size()<<'\n';

        for(auto it:ans)
        {
            cout<<it.first<<" "<<it.second<<'\n';
        }
    }
    return 0;
}

 

 dp[i][j]代表i长度时,以j结尾的方案数。而转移方程的获得,观察样例解释最方便获得。即dp[i][j]由全部的dp[i-1][k]  1<=k<=j获得。 其中特别注意的是j的下限,它等于前i个数字由高到低放置的时候的结尾数字。其实也就是sort之后的ai。这里的ai,是我们事先离散化好的。

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll dp[3030][3030];
# define mod 1000000007
int a[3030],lisan[3030],len;
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;
        len=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            len++;
            lisan[len]=a[i];
        }
        sort(a+1,a+1+n);
        sort(lisan+1,lisan+1+len);
        len=unique(lisan+1,lisan+1+len)-lisan-1;
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=len;j++)
            {
                dp[i][j]=0;
            }
        }

        for(int i=1;i<=len;i++)
        {
            dp[1][i]=1;
        }
        ll ans=0;
        for(int i=2;i<=n+1;i++)
        {
            for(int j=1;j<=len;j++)
            {
                dp[i-1][j]+=dp[i-1][j-1];
                dp[i-1][j]%=mod;
            }
            int l=lower_bound(lisan+1,lisan+1+len,a[i])-lisan;
            for(int j=l;j<=len;j++)
            {
                dp[i][j]+=dp[i-1][j];
                dp[i][j]%=mod;
            }

            cout<<dp[i-1][len]<<'\n';
        }
    }

    return 0;
}

 

 

题解所说的2-sat+二分+排序+贪心+ Kosaraju解法,过于复杂冷门,且没有充分利用题目条件,即替代方案的a,b,c都大于原始方案的a,b,c。利用这一性质,考虑贪心做法,每次我们获取当前a,b,c最大极差,将造成这一最大极差两个数,小的那个,替换为“替代方案”,也就缩小的极差。这一过程用set维护只需要几十行,复杂度低,常数小,优于题解上百行的2-sat。

而对于题解的2-sat。即二分最终答案,Kosaraju边跑边建图。正向DFS时,当前点只走向冲突点的反点,反向遍历时,获取当前反点的冲突点。而后检查点和反点是否在同一强联通。对于tarjan为什么不能这样写,尚未理解。赛时也没有tarjan过掉的。

 

#include<bits/stdc++.h>
using namespace std;

set<pair<int,int>>s[4];
int book[100000+10];
int a[200000+10][4];
int main()
{
    cin.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--)
    {
        int n;
        cin>>n;

        for(int i=1;i<=n;i++)
        {
            book[i]=0;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=3;j++)
            {
                cin>>a[i][j];
            }
            for(int j=1;j<=3;j++)
            {
                cin>>a[i+n][j];
            }
        }
        for(int i=1;i<=3;i++)
            s[i].clear();

        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=3;j++)
            {
                s[j].insert({a[i][j],i});
            }
        }
        int ans=2e9+10;

        while(1)
        {
            int temp[4];
            int maxx=0;
            for(int i=1;i<=3;i++)
            {
                temp[i]=(s[i].rbegin()->first-s[i].begin()->first);
                maxx=max(maxx,temp[i]);
            }
            int flag=0;

            ans=min(ans,maxx);

            for(int i=1;i<=3;i++)
            {
                if(temp[i]==maxx)
                {
                    auto [val,id]= *s[i].begin();
                    if(id<=n)
                    {
                        if(book[id]==0)
                        {
                            book[id]=1;

                            for(int j=1;j<=3;j++)
                            {
                                s[j].erase({a[id][j],id});

                                s[j].insert({a[id+n][j],id+n});
                                flag=1;
                            }
                            break;
                        }
                    }

                }
            }
            if(flag==0)
                break;

        }

        cout<<ans<<'\n';
    }

    return 0;
}

 

模拟即可,注意原图有“颜色块”可以不呈整数倍扩增时,也是可以的。二维前缀和暴力搞就是

 

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char ans[500][500], a[500][500];
int sum[500][500][30];
int getsum(int x,int y,int xx,int yy,int ch)
{
    return sum[xx][yy][ch]-sum[xx][y-1][ch]-sum[x-1][yy][ch]+sum[x-1][y-1][ch];
}
int main()
{
    int t;
    cin>>t;

    while(t--)
    {
        int n, z;
        scanf("%d%d", &n, &z);
        int flag = 0 ;
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                for(int k=1; k<=26; k++)
                {
                    sum[i][j][k]=0;
                }
            }
        }
        char ch = '1';
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j<=n; j++)
            {
                cin >> a[i][j];
                if(ch=='1')
                {
                    ch = a[i][j];
                }
                else if(a[i][j]!=ch)
                {
                    flag = 1;
                }
                int now=(int)(a[i][j]-'a'+1);
                for(int k=1; k<=26; k++)
                {
                    sum[i][j][k]=sum[i][j-1][k]+sum[i-1][j][k]-sum[i-1][j-1][k]+(now==k);
                }
            }
        }
        int temp = n * z;
        if(temp%100)
        {
            cout<<"error"<<endl;
            continue;
        }
        else
        {
            temp /= 100;
            if(temp%n)
            {
                int flag=0,flag1=0;
                for(int x=1; x<=n; x++)
                {
                    if(n%x==0)
                    {
                        int fuck=(x*temp);
                        if(fuck%n)
                            continue;
                        fuck/=n;
                        if(temp%fuck)
                            continue;
                        int nowfuck=0;
                        for(int i=1; i*x<=n; i++)
                        {
                            for(int j=1; j*x<=n; j++)
                            {
                                int xxx=(i-1)*x+1;
                                int yyy=(j-1)*x+1;
                                int xx=i*x;
                                int yy=j*x;
                                int now=(int)(a[xxx][yyy]-'a'+1);
                                if(getsum(xxx,yyy,xx,yy,now)!=x*x)
                                {
                                    nowfuck=1;
                                }
                            }
                        }
                        if(nowfuck==0)
                        {
                            flag=x;
                            flag1=fuck;
                            break;
                        }
                    }
                }
                if(flag==0)
                {
                    cout<<"error"<<endl;
                    continue;
                }
                else
                {
                    int x=flag;
                    for(int i=1; i*x<=n; i++)
                    {
                        for(int j=1; j*x<=n; j++)
                        {
                            int xxx=(i-1)*x+1;
                            int yyy=(j-1)*x+1;
                            int nowhang=(i-1)*flag1+1;
                            int nowhang1=i*flag1;
                            int nowlie=(j-1)*flag1+1;
                            int nowlie1=j*flag1;
                            for(int ii=nowhang; ii<=nowhang1; ii++)
                            {
                                for(int jj=nowlie; jj<=nowlie1; jj++)
                                {
                                    ans[ii][jj]=a[xxx][yyy];
                                }
                            }
                        }
                    }
                    for(int i=1; i<=temp; i++)
                    {
                        for(int j=1; j<=temp; j++)
                        {
                            cout<<ans[i][j];
                        }
                        cout<<'\n';
                    }
                }
            }
            else
            {
                int nowhang = 0, nowhang1 = 0, nowlie = 0, nowlie1 = 0;
                int cha = temp / n;
                for (int i = 1; i <= n; i++)
                {
                    nowhang = (i - 1) * cha + 1;
                    nowhang1 = (i)*cha;
                    for (int j = 1; j <= n; j++)
                    {
                        nowlie = (j - 1) * cha + 1;
                        nowlie1 = (j)*cha;

                        for (int ii = nowhang; ii <= nowhang1; ii++)
                        {
                            for (int jj = nowlie; jj <= nowlie1; jj++)
                            {
                                ans[ii][jj] = a[i][j];
                            }
                        }
                    }
                }
                for (int i = 1; i<=temp; i++)
                {
                    for (int j = 1; j<=temp; j++)
                    {
                        cout << ans[i][j];
                    }
                    cout << '\n';
                }
            }
        }
    }
    return 0;
}

 

Problem - 7311

 

 

 首先这一变换具有一个性质,即除了原始的a,b的大小关系不定外,处于“变化”过程中的a,b是有确定的大小关系的,且可以根据这一大小关系直接推出上一步的变换。我们可以将已知的a,b统一向前倒推,这一方法便是辗转相减,最终会得出gcd。不难发现,这一轨迹的形态,是一颗树。同时,我们对询问的a,b也这样转换。画图易知,一个A,B能够转化为,a,b当且仅当A,B轨迹是a,b轨迹的前缀。

而进一步将前缀关系转化为字典序关系。我们将向左拐为-1,右拐为-2,虚点为0.A,B轨迹确定时,AB为前缀的全部轨迹在,大于等于AB字典序,小于AB+虚点0字典序的范围内。

故可以对已知和询问统一放在一个集合排序,排序规则自定义模拟。字典序相同时,已知的放在后面,询问的放在在前。 

这样排序,遇到AB+0时计算当前已知的个数,遇到AB是计算已知个数,二者相减,即可得出答案,也就是大于等于AB,小于AB+0的,减去严格小于AB的。差分的思想,线性解决。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
inline ll read()
{
    ll x = 0, f = 1ll;
    char ch = getchar();
    while (!isdigit(ch))
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (isdigit(ch))
    {
        x = (x << 1ll) + (x << 3ll) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}

inline void write(ll x)
{
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}

struct node
{
    int ti;
    vector<ll>v;
};
struct node s[500000*3+10];
inline vector<ll>work(ll x,ll y)
{
    vector<ll>ans;
    while(x!=y)
    {
        if(x>y)
        {
            ll pre=x;
            x%=y;
            if(x==0)
                x=y;

            ans.push_back((pre-x)/y);
            ans.push_back(-1);//左转
        }
        else
        {
            ll pre=y;
            y%=x;
            if(y==0)
                y=x;
            ans.push_back((pre-y)/x);
            ans.push_back(-2);
        }
    }
    ans.push_back(x);
    reverse(ans.begin(),ans.end());
    return ans;
}
inline int check(const vector<ll>&a,const vector<ll>&b)
{
    int n=a.size(),m=b.size(),i;
    if(a[0]!=b[0])return a[0]<b[0]?-1:1;
    for(i=1; i<n&&i<m; i+=2)
    {
        if(a[i]!=b[i])return a[i]<b[i]?-1:1;
        if(!a[i])return 0;
        if(a[i+1]<b[i+1])
        {
            if(i+2>=n)return -1;
            return a[i+2]<b[i]?-1:1;
        }
        if(a[i+1]>b[i+1])
        {
            if(i+2>=m)return 1;
            return a[i]<b[i+2]?-1:1;
        }
    }
    if(i<n)return 1;
    if(i<m)return -1;
    return 0;
}
 bool cmp(struct node &x, struct node &y)
{
    int temp=check(x.v,y.v);
    if(temp==-1)
        return 1;
    if(temp==1)
        return 0;
    return x.ti<y.ti;
}
int ans[500000+10];
int main()
{

    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        n=read();
        m=read();
        int len=0;
        for(int i=1; i<=n; i++)
        {
            ll a,b;
            a=read();
            b=read();
            len++;
            s[len].ti=0;
            s[len].v=work(a,b);
        }
        for(int i=1; i<=m; i++)
        {
            ll a,b;
            ans[i]=0;
            a=read();
            b=read();
            len++;
            s[len].ti=-i;
            s[len].v=work(a,b);
            len++;
            s[len].ti=i;
            s[len].v=s[len-1].v;
            s[len].v.push_back(0);
            s[len].v.push_back(0);
        }
        sort(s+1,s+1+len,cmp);
        int nowcnt=0;
        for(int i=1; i<=len; i++)
        {
            if(s[i].ti==0)
            {
                nowcnt++;
                continue;
            }
            if(s[i].ti<0)
                ans[-s[i].ti]-=nowcnt;
            else
                ans[s[i].ti]+=nowcnt;
        }
        for(int i=1; i<=m; i++)
        {
            cout<<ans[i]<<'\n';
        }

        for(int i=1; i<=len; i++)
        {
            s[i].v.clear();
        }
    }
    return 0;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

2023“钉耙编程”中国大学生算法设计超级联赛(3) 的相关文章

  • pluto实现分析(5)

    本文档的Copyleft归yfydz所有 使用GPL发布 可以自由拷贝 转载 转载时请保持文档的完整性 严禁用于任何商业用途 msn yfydz no1 hotmail com 来源 http yfydz cublog cn 7 内核接口

随机推荐

  • ABAP 发邮件(三)

    转自http blog sina com cn s blog 7c7b16000101bnxk html SAP ABAP 发邮件方法三 OO Report ZSENDEMAIL08 REPORT zsendemail08 CONSTANT
  • R:数据对象及类型

    数据对象 R语言创建和控制的实体被称为对象 object 它们可以说变量 数组 字符串 函数或者其它通过这些实体定义的更一般的结构 structures 在R语言里 对象是通过名字创建和保存的 R对象的名称必须以一个英文字母打头 并由一串大
  • 【Vue】动态监听localStorage或sessionStorage中数据的变化:

    1 需求 一个页面数据变化要改变另一个页面 甚至整个项目的数据变化 2 在main js中 description 监听本地储存的值变化 param number type 1 localStorage 2 sessionStorage p
  • QT在vs2019上配置流程

    一 安装VS2019 2 安装Qt5 15 VS2019只能安装QT5 14版本以上 5 15版本以上需要在在线安装平台下载安装 在QT官网https download qt io 中找到official releases gt onlin
  • Anaconda安装深度学习框架(TensorFlow,Pytorch)教程

    有道云链接 1 用anaconda创建虚拟环境 在这之前 我们需要确定服务器上安装了anaconda 使用下面命令查看 whereis anaconda anaconda data softwares opt anaconda2 bin a
  • 单例模式的几种实现

    单例模式的几种实现 在开发中 我们总是会遇到使用单例模式的情况 今天就来总结一下几种实现单例模式的方法 1 饿汉式 public class SingletonDemo1 类初始化时 立即加载该对象 没有延时加载的优势 由于加载类时 天然的
  • VIM查看使用的配置文件

    最近在配置NeoVim 配置文件怎么放都不对 最后只能想办法找它用的哪一个配置文件 可以使用stdpath把它的配置文件路径回显一下 echo stdpath config 如果不清楚stdpath怎么使用 可以直接调一下help stdp
  • 华为OD机试真题- 取出尽量少的球【2023Q2】【JAVA、Python、C++】

    题目描述 某部门开展Family Day开放日活动 其中有个从桶里取球的游戏 游戏规则如下 有N个容量一样的小桶等距排开 且每个小桶都默认装了数量不等的小球 每个小桶所装的小球数量记录在数组bucketBallNums中 游戏开始时 要求所
  • 使用Hibernate连接MySQL数据库,MySQL连接超时断开的问题

    最近让人头疼的一个问题 就是服务器在不确定的时点会出现关于数据库连接的Exception 大致的Exception如下 org hibernate util JDBCExceptionReporter SQL Error 0 SQLStat
  • texstudio配置编译路径

    texstudio必须配置好编译路径 否则无法编译运行 选项 设置 命令 pdflatex 点击打印符号 找到pdflatex exe打开即可 Xelatex操作步骤相同
  • tomcat替换class文件后重启不生效问题记录

    清空Tomcat work catalina 里面的内容 清空Tomcat temp里面的内容 将Tomcat class文件中 引用 被修改的class 的那几个方法的class 都替换一下 正确操作 但是依然不生效 发现了问题但是不知道
  • 编码:KR字符串匹配,一个简单到领导都看得懂的算法

    常怀感恩 生活或许就不会处处深渊 这几天看了 柔性字符串匹配 觉得很有意思 书是好书 只是这个脑子是不是猪脑就不知道了 于是秉着知之为知之 不知为不知的精神 我准备再次去请教一下我的领导 在一个月黑风高的夜晚 我给领导发了个消息 领导这么回
  • 2023自动化测试需知的4项测试工具!

    一般来说学自动化会建议大家先学selenium 因为最早的时候 自动化就代表selenium 进入测试行业就开始做接口测试 而且现在基本每个公司都需要接口测试 今天就和大家聊一下接口测试的工具 一 Robot Framework 机器人框架
  • Ubuntu添加和设置默认中文字体

    参考 https blog csdn net gengyuchao article details 101215243 首先 通过命令 fc list lang zh 可以查看已安装的中文字体 默认为Ubuntu系统自带的中文字体 安装新字
  • x的n次幂

    题目描述 实现 pow x n 即计算 x 的 n 次幂函数 样例 输入 2 00000 10 输出 1024 00000 说明 100 0 lt x lt 100 0 n 是 32 位有符号整数 其数值范围是 2147483648 214
  • NexT 主题自定义侧边栏图标

    NexT 主题的图标基本上都是由 Font Awesome 提供 但是知乎 CSDN bilibili等大多数国内应用软件的图标在Font Awesome都不支持 为了支持侧边栏各种应用小图标的显示 可以利用嵌入svg格式的图标进行实现 本
  • keil5编译器出现Undefined symbol time (referred from xxx.o).

    我前不久再弄基于stm32控制智能小车电机时 经常出现 error Undefined symbol time referred from xxx o 很烦人 后来我发现了解决办法 在这里我要分享给大家 方法 直接在xxx c文件中给tim
  • Nim游戏详解

    文章目录 废话 正题 证明 举个栗子 拓展题 废话 这是一个过于经典且过于常见的博弈论模型 入门博弈论的话 首先肯定是要知道这个的 正题 N i m Nim Nim 游戏的规则 有 n
  • 数据结构和算法(4)-----栈

    一 栈的一个实际需求 例如 请输入一个表达式计算式 7 2 2 5 1 5 3 3 点击计算 如下图 请问 计算机底层是如何运算得到结果的 注意不是简单的把算式列出运算 因为我们看这个算式 7 2 2 5 但是计算机怎么理解这个算式的 对计
  • 2023“钉耙编程”中国大学生算法设计超级联赛(3)

    Chaos Begin 贪心 凸包 Out of Control DP 递推 Operation Hope 贪心 2 sat与二分 8 bit Zoom 二维前缀 Noblesse Code 轨迹哈希 字典序 差分 Problem 7303