首页 > 其他分享 >P10315 解题报告

P10315 解题报告

时间:2024-09-11 19:35:08浏览次数:14  
标签:报告 int 石碑 ++ cdots 解题 ans P10315 mod

题目传送门

题目大意:

有 \(n\) 个石碑,每个石碑有 \(0\sim m - 1\) 共 \(m\) 种状态,击打一个石碑会带动其他的石碑。若当前石碑的状态是 \(s\),则击打或被带动后的状态为 \((s + 1)\bmod m\)。

现给定这 \(n\) 个石碑的初始状态 \(s_i\)、每个石碑带动的石碑及末状态 \(t_i\),求每个石碑至少被击打几次。

思路:

首先把题面意思抽象出来,令 \(a_{i, j}\) 表示第 \(i\) 个石碑和第 \(j\) 个石碑的联系,若 \(a_{i, j} = 1\),则表示击打 \(j\) 会带动 \(i\),若 \(a_{i, j} = 0\) 表示无影响,特别的,因为击打自己就相当于带动自己,所以 \(a_{i, i} = 1\)。

再令 \(x_i\) 表示第 \(i\) 个石碑被击打的次数。

那么题面就变为了:

\[\left\{\begin{matrix} s_1 + a_{1, 1}x_1 + a_{1, 2}x_2 + \cdots + a_{1, n}x_n \equiv t_1\pmod m\\ s_2 + a_{2, 1}x_1 + a_{2, 2}x_2 + \cdots + a_{2, n}x_n \equiv t_2\pmod m\\ \cdots\\ s_n + a_{n, 1}x_1 + a_{n, 2}x_2 + \cdots + a_{n, n}x_n \equiv t_n\pmod m \end{matrix}\right.\]

再移个项,得:

\[\left\{\begin{matrix} a_{1, 1}x_1 + a_{1, 2}x_2 + \cdots + a_{1, n}x_n \equiv t_1 - s_1\pmod m\\ a_{2, 1}x_1 + a_{2, 2}x_2 + \cdots + a_{2, n}x_n \equiv t_2 - s_2\pmod m\\ \cdots\\ a_{n, 1}x_1 + a_{n, 2}x_2 + \cdots + a_{n, n}x_n \equiv t_n - s_n\pmod m \end{matrix}\right.\]

求出每个 \(x_i\) 的最小非负整数解即可。

同余只是纸老虎!直接转换成等号,高斯消元求解即可,只是需要把解映射到 \([0, m - 1]\)。

同时这道题还需要在无穷多组解时输出任意一组解,需要在消元时额外注意(其实应该只有我这种写法应该注意),不能直接回代求解。

当找到一个主行 \(r\) 时,不要只从 \(r + 1\) 消到 \(n\),而应该把 \(1\sim n\) 都消一遍,此时除每行的首变量(每个行向量中第一个系数非零的未知数)之外其他的都是自由元,直接将首变量赋值,自由元赋成 \(0\) 不管就行了。

这是我原来的高斯消元代码:

int gauss() {
    int c, r;
    for(c = 0, r = 0; c < n; c++) {
        int t = r;
        for(int i = r + 1; i < n; i++)
            if(abs(a[i][c]) > abs(a[t][c]))
                t = i;
        if(!a[t][c]) continue;

        if(t != r) for(int i = c; i <= n; i++) swap(a[t][i], a[r][i]);
        for(int i = n; i >= c; i--) a[r][i] = (a[r][i] * (qpow(a[r][c], mod - 2) + mod) % mod) % mod;

        for(int i = r + 1; i < n; i++) //原来是消第 r + 1 到 n 行
            if(a[i][c])
                for(int j = n; j >= c; j--)
                    a[i][j] = (mod + a[i][j] - a[i][c] * a[r][j] % mod) % mod;
        ++r;
    }
    if(r < n) {
        for(int i = r; i < n; i++)
            if(a[i][n] > 0)
                return -1;
    }
    for(int i = n - 2; ~i; i--)
        for(int j = i + 1; j < n; j++)
            a[i][n] = (mod + a[i][n] - a[i][j] * a[j][n] % mod) % mod;
    return 1; 
}

它在这组数据时会出错:

3 3
2 2 3
2 1 3
1 1
0 0 0
2 1 2

Answer:
0 1 1
或:
1 0 1

My answer:
1 1 0

原矩阵:

\[\left[\begin{array}{ccc|c} 1 & 1 & 1 & 2\\ 1 & 1 & 0 & 1\\ 1 & 1 & 1 & 2 \end{array}\right] \]

这是因为用以上代码消出来的结果为:

\[\left[\begin{array}{ccc|c} 1 & 1 & 1 & 2\\ 0 & 0 & 1 & 1\\ 0 & 0 & 0 & 0 \end{array}\right] \]

而如果直接回代就会直接将 \(x_3\) 钦定为 \(0\),这是不对的,因为 \(x_2\) 才是自由元,而 \(x_3\) 有固定的解 \(1\)。

而采用全部重消一遍的方法就能保证所有首变量都只会在一个行向量中出现,这时候回代就完全不用考虑和其他首变量取值出现冲突的问题。

\(\texttt{Code:}\)

#include <cmath>
#include <iostream>

using namespace std;

const int N = 110;
typedef long long ll;
int n, mod;
ll a[N][N];
ll ans[N];

ll qpow(ll a, int b) {
    ll ans = 1, base = a % mod;
    while(b) {
        if(b & 1) ans = ans * base % mod;
        base = base * base % mod;
        b >>= 1;
    } 
    return ans;
}

void output() {
    puts("---------");
    for(int i = 0; i < n; i++) {
        for(int j = 0; j <= n; j++)
            printf("%d ", a[i][j]);
        puts("");
    }
    puts("---------");
}

int gauss() {
    int c, r;
    for(c = 0, r = 0; c < n; c++) {
        int t = r;
        for(int i = r + 1; i < n; i++)
            if(abs(a[i][c]) > abs(a[t][c]))
                t = i;
        if(!a[t][c]) continue;

        if(t != r) for(int i = c; i <= n; i++) swap(a[t][i], a[r][i]);
        for(int i = n; i >= c; i--) a[r][i] = (a[r][i] * (qpow(a[r][c], mod - 2) + mod) % mod) % mod;

        for(int i = 0; i < n; i++) //全部重消一遍
            if(a[i][c] && i != r)
                for(int j = n; j >= c; j--)
                    a[i][j] = (mod + a[i][j] - a[i][c] * a[r][j] % mod) % mod; //注意取模时要加上模数以防负数
        ++r;
    }
    if(r < n) {
        for(int i = r; i < n; i++)
            if(a[i][n] > 0)
                return -1;
        //
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < n; j++)
                if(a[i][j]) { //寻找首变量
                    ans[j] = a[i][n]; //直接将首变量赋成方程右侧的值,其他变量都是自由元,直接赋成 0
                    break;
                }
        }
        return 0;
    }
    for(int i = n - 2; ~i; i--)
        for(int j = i + 1; j < n; j++)
            a[i][n] = (mod + a[i][n] - a[i][j] * a[j][n] % mod) % mod;
    for(int i = 0; i < n; i++)
        ans[i] = a[i][n];
    return 1; 
}


int main() {
    scanf("%d%d", &n, &mod);
    ll x;
    for(int i = 0; i < n; i++) {
        int cnt;
        scanf("%d", &cnt);
        while(cnt--) {
            scanf("%lld", &x);
            a[x - 1][i] = 1;
        }
        a[i][i] = 1;
    }
    for(int i = 0; i < n; i++)
        scanf("%lld", &a[i][n]);
    for(int i = 0; i < n; i++) {
        scanf("%lld", &x);
        a[i][n] = x - a[i][n];
    }
    int type = gauss();
    if(type >= 0)
        for(int i = 0; i < n; i++)
            printf("%lld ", ans[i]);
    else puts("niuza");
    return 0;
}

标签:报告,int,石碑,++,cdots,解题,ans,P10315,mod
From: https://www.cnblogs.com/Brilliant11001/p/18408820

相关文章

  • P7976 解题报告
    题目传送门题目大意:设函数\(F(x):=(x+1)\bmod3−1\),\(T\)次询问,计算:\[\sum\limits_{i=0}^{n}\sum\limits_{j}F\left({i\choosej}\right)\]思路:看到奇奇怪怪的组合数求和首先考虑\(\text{Lucas}\),将原数在\(3\)进制下拆位,得:\[{i\choosej}=\prod\limits_{k......
  • 基于OpenSSL的密码管理系统-应用密码学课程报告
    第1章概要设计1.1设计目的本研究旨在设计并实现一个基于OpenSSL的密码管理系统,该系统具备密钥对的生成、密钥上传、密钥的核对、身份认证、文件与邮件的加密和解密、数字签名及数字证书管理等常用功能。研究的意义主要体现在以下几个方面:提升网络信息安全水平:通过集成多种密......
  • CTF学习-MISC杂项解题思路
    文件操作与隐写文件类型识别 1.File命令当文件没有后缀名或者有后缀名而无法正常打开时,根据识别出的文件类型来修改后缀名即可正常打开文件。使用场景:不知道后缀名,无法打开文件。格式:filemyheart2.winhex通过winhex.程序中可以查看文件头类型,根据文件头类型判断出......
  • 井下甲烷气体报警器研发(工程教育课程项目报告)
    目录井下甲烷气体报警器研发......................................................................................3一、   项目概况..............................................................................................31.    项目内容...........
  • 【看雪-注册安全分析报告】
    前言由于网站注册入口容易被黑客攻击,存在如下安全问题:暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞所以大部分网站及App都采取图形验证码或滑动验证码等交互解决方案,但在机器学习能力提......
  • 软件项目管理资料总汇(规格说明书;详细设计;测试计划;验收报告)
      前言:在软件开发过程中,文档资料是非常关键的一部分,它们帮助团队成员理解项目需求、设计、实施、测试、验收等各个环节,确保项目的顺利进行。以下是各个阶段的文档资料概述:软件项目管理部分文档清单: 工作安排任务书,可行性分析报告,立项申请审批表,产品需求规格说明书,需求调......
  • 【专题】2024年中国折叠屏手机市场与消费趋势研究报告合集PDF分享(附原数据表
    原文链接:https://tecdat.cn/?p=37645中国智能手机市场目前仍处于整体增长瓶颈期,增长复苏未达预期,消费者换机预期周期不断延长,使得行业对破局点的探寻更为紧迫。与此同时,中端消费者购机呈现出消费降级与升级的分化态势,不过更多人会选择体验更好、配置更优的产品以延长使用时间。ID......
  • 数据结构实验报告1(集合)
    学习目标:        掌握抽象数据类型的表示与实现方法。学习内容:        描述一个集合的抽象数据类型ASet,其中所有元素为整数且所有元素不相同,集合的基本操作包括:由整数数组a[0..n-1]创建一个集合。输出集合中的所有元素。判断一个元素是否在一个集合中。求......
  • 基于django+vueblockly少儿编程在线学习网站【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,编程教育逐渐从高等教育向基础教育渗透,成为培养未来社会创新人才的重要途径。少儿编程作为这一趋势的前沿阵地,其重......
  • 基于django+vueATM自动取款机系统【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和金融服务的日益普及,自动取款机(ATM)系统已成为现代银行服务不可或缺的一部分。ATM系统不仅极大地提升了金融交易的......