java div2_Codeforces #641 div2 A - E 解题报告

\(Description:\)

设 \(f(n)\) 是 \(n\) 的最小约数 \((f(n) > 1)\)。那么对于一次操作而言 \(n = n + f(n)\),求第 \(k\) 次操作后,\(n\) 为多少?

\(Solution:\)

对于 \(n\) 是偶数的情况下,\(f(n) = 2\),那么加上 \(f(n)\) 后 \(n\) 任然是偶数,所以每次都 \(+ 2\)。

对于 \(n\) 是奇数的情况下,\(f(n)\) 也一定是奇数,那么加上 \(f(n)\) 后,\(n\) 就变成了偶数。

\(Code:\)

#include

using namespace std;

typedef long long ll;

int main(){

int t; cin >> t;

while(t --){

ll n, k;

cin >> n >> k;

if(n & 1){

int mark = 0;

for(int i = 2; i * i <= n; i ++){

if(n % i == 0){

n += i;

mark = 1;

break;

}

}

if(!mark) n += n;

cout << n + (k - 1) * 2 << endl;

}else{

cout << n + k * 2 << endl;

}

}

return 0;

}

\(Description:\)

给定一个长为 \(n\) 的数组 \(a\),在数组挑选几个数组成一个新序列,要求新序列的任意两个数要满足:\(j\ mod\ i = 0\ and\ a_i < a_j\),\(i, j\) 是该数在原数组的下标。

\(Solution:\)

设 \(f[i]\) 为以 \(a_i\) 结尾的构成合法新序列的最长长度。那么我们去枚举 \(i\) 的约数 \(j\),于是得到:\(f[i] = max(f[i], f[j] + 1)\)。

\(Code:\)

#include

using namespace std;

const int N = 1e5 + 10;

int n;

int s[N], f[N];

int main(){

int t; cin >> t;

while(t --){

cin >> n;

for(int i = 1; i <= n; i ++)

scanf("%d", &s[i]);

for(int i = 1; i <= n; i ++){

f[i] = 1;

for(int j = 1; j * j <= i; j ++){

if(i % j == 0){

if(s[i] > s[j])

f[i] = max(f[i], f[j] + 1);

if(s[i] > s[i / j])

f[i] = max(f[i], f[i / j] + 1);

}

}

}

cout << *max_element(f + 1, f + n + 1) << endl;

}

return 0;

}

\(Description:\)

给定长度为 \(n\) 的数组 \(a\),求由 \((lcm(a_i, a_j)\ |\ i < j)\) 得到一些数的 \(gcd\)。

\(Solution:\)

单独看 \(a_1\),我们可以得到 \(lcm(a_1,a_2),lcm(a_1,a_3),...,lcm(a_1,a_n)\)。则:

\[gcd(lcm(a_1,a_2),\ lcm(a_1,a_3),\ ...,\ lcm(a_1,a_n)) = lcm(a_1,\ gcd(a_2,\ a_3,...,\ a_n)) \]

我们预处理出一个 \(gcd\) 的后缀,就可以简单的得出结果。

证明一下上面的公式:

假设:\(lcm(a_1, a_2) = a_1 \times a_2 \times x_2\),那么 \(x_2 = 1/gcd(a_1,a_2)\);

同理:\(lcm(a_1,a_3) = a_1 \times a_3 \times x_3\);那么 \(x_3 = 1/gcd(a_1,a_3)\);

那么设: \(t = gcd(lcm(a_1,a_2),lcm(a_1,a_3)) = gcd(a_1 \times a_2 \times x_2, a_1 \times a_3 \times x_3) = a_1 \times gcd(a_2 \times x_2, a_3 \times x_3)\)。

因为:\(gcd(a \times x, b \times y)= gcd(a, b) \times gcd(x, y)\);

所以:\(t = a_1 \times gcd(a_2, a_3) \times gcd(x_2, x_3)\)

\(t = a_1 \times gcd(a_2, a_3) \times gcd(1/gcd(a_1,a_2), 1/gcd(a_1, a_3))\)

由:\(gcd(1/a, 1/b) = 1/gcd(a, b)\);

则:\(t = a_1 \times gcd(a_2, a_3) / gcd(gcd(a_1,a_2), gcd(a_1,a_3))\);

又因为 \(gcd(gcd(a, b), gcd(a, c)) = gcd(a, gcd(b, c))\);

所以:\(t = a_1 \times gcd(a_2, a_3) / gcd(a_1, gcd(a_2,a_3)) = lcm(a_1, gcd(a_2,a_3))\);

证毕。

\(Code:\)

#include

using namespace std;

const int N = 1e5 + 10;

typedef long long ll;

int n;

ll a[N], g[N];

ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }

ll lcm(ll a, ll b) { return a * b / gcd(a, b); }

int main(){

cin >> n;

for(int i = 1; i <= n; i ++)

scanf("%d", &a[i]);

g[n + 1] = 0;

for(int i = n; i >= 1; i --)

g[i] = gcd(g[i + 1], a[i]);

ll ans = 0;

for(int i = 1; i < n; i ++){

ll tmp = lcm(a[i], g[i + 1]);

ans = gcd(ans, tmp);

}

cout << ans << endl;

return 0;

}

\(Description:\)

给定长为 \(n\) 的数组 \(a\) 和一个 \(k\),,问是否可以通过任意次操作将数组每个元素变为 \(k\)?

操作是:将数组区间 \([l, r]\) 的数变为该区间的中位数。

\(Solution:\)

很显然的一个判断是确认数组中有没有 \(k\) 这个元素。

对于中位数的确认,显然涉及到了排序,但是时间不允许。但是如果我们只考虑长度 \(2\) 的区间,显然小的那个数就是中位数。那么对于固定的 \(k\) 来说,我们只需要他的左边或右边存在一个 \(\geq k\) 的数,那么就可以变为 \(k\),那么此时我们就得到了两个连续的 \(k\),那么我们在这个区间上去扩展一个元素,即区间长度为 \(3\),无论第三个元素的大小,中位数都一定是 \(k\),那么我们就得到了三个连续的 \(k\),以此类推下去我们就可以构造出来了。

那么我们接下来的任务就是在 \(k\) 的左边或右边搞出一个 \(\geq k\) 的数,那么我们根据上面的思路,如果存在两个连续的数 \(\geq k\),那么我们就可以扩展到三个数,四个数......直到遇到扩展的元素为 \(k\)。

那么我们就得到了一个条件:存在两个连续的数 \(\geq k\);

如果不满足上述条件是不是就一定不可以了呢?对于这种情况:\(a_i, a_{i+1}, a_{i+2},(a_i \geq k, a_{i+1} < k, a_{i+2} \geq k)\),显然也是可以的。所以只要满足这两个条件就可以了。

还有一个坑点就是要特判 \(n = 1\) 的情况。

\(Code:\)

#include

using namespace std;

const int N = 1e5 + 10;

int n, k;

int a[N];

bool judge(){

int mark = 0;

for(int i = 1; i <= n; i ++){

if(a[i] == k) mark = 1;

}

if(!mark) return 0;

if(n == 1 && a[n] == k) return 1;

for(int i = 2; i <= n; i ++){

if(a[i] >= k && a[i - 1] >= k) return 1;

if(i >= 3 && a[i] >= k && a[i - 2] >= k) return 1;

}

return 0;

}

int main(){

int t; cin >> t;

while(t --){

cin >> n >> k;

for(int i = 1; i <= n; i ++)

scanf("%d", &a[i]);

if(judge()) puts("yes");

else puts("no");

}

return 0;

}

\(Description:\)

给出一个 \(0, 1\) 矩阵,每经过一轮循环矩阵就有可能变换。

\(1.\) 如果一个元素存在一个相邻元素和他相同,那么该元素就会变换。

\(2.\) 如果不存在,那么该轮循环就不会发生变换。

\(Solution:\)

显然的一个事实是:如果矩阵中不存在一组相邻的元素相同,那么矩阵就永远不会变。否则,矩阵的每一位元素都有可能发生变换,可以参考样例三。

那么我们只需要把那些可以发生变换的元素提取出来,然后用他们去同化那些原本不会变的元素即可,记录下每个元素的第一次变换的循环是那一次即可。

\(Code:\)

#include

using namespace std;

const int N = 1e3 + 10, INF = 0x3f3f3f3f;

typedef pair PII;

typedef long long ll;

int n, m, t;

char s[N][N];

int a[N][N];

int vis[N][N];

int d[N][N];

int to[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

int check(int x, int y){

if(x >= 1 && x <= n && y >= 1 && y <= m) return 1;

return 0;

}

int main(){

cin >> n >> m >> t;

for(int i = 1; i <= n; i ++)

scanf("%s", s[i] + 1);

memset(vis, 0, sizeof vis);

memset(d, INF, sizeof d); // 第一次变换的循环

queue q;

for(int i = 1; i <= n; i++)

for(int j = 1; j <= m; j ++){

a[i][j] = s[i][j] - '0';

for(int k = 0; k < 4; k ++){

int x = i + to[k][0];

int y = j + to[k][1];

if(check(x, y) && s[x][y] == s[i][j]){

q.push({i, j}); // 提取存在相邻相同元素的

d[i][j] = 0; // 置为 0,因为原本就会变

vis[i][j] = 1; // 标记已经访问过

break;

}

}

}

while(!q.empty()){

PII t = q.front(); q.pop();

int x = t.first, y = t.second;

for(int i = 0; i < 4; i ++){ // 用这个元素去同化他周围的

int xx = x + to[i][0];

int yy = y + to[i][1];

if(check(xx, yy) && !vis[xx][yy]){

q.push({xx, yy});

d[xx][yy] = d[x][y] + 1;

vis[xx][yy] = 1; // 标记一下

}

}

}

while(t --){

int x, y;

ll p; // p 很大

scanf("%d%d%lld", &x, &y, &p);

p -= d[x][y]; // 减去需要同化的循环次数

if(p <= 0 || d[x][y] == INF) printf("%d\n", a[x][y]);

else printf("%d\n", a[x][y] ^ (p & 1));

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
旋转变压器---数字转换器作为现代伺服系统中被广泛使用的角位置测量系统,大量应用于高精度及大中型数控系统、机器人控制、工业控制、武器火力控制及惯性导航领域中。 传统的角测量系统面临的问题有:体积、重量、功耗偏大,调试、误差补偿试验复杂,费用较高。本文从微型化、智能化的方向进行研究,是解决传统角测量系统所面临问题的好途径。 本文所研究的旋转变压器---数字转换器是由信号调理模块、系统芯片C8051F064和输出控制模块组成的。整个系统的三路输入信号为X=AsinOcosar、Y=Acosθcos ot和Z=Ucosar(基准信号),输出信号为偏转角θ,输出形式为16 位数字量。信号调理模块是由模拟电路组成的,包括信号输入电路、相敏整流电路、滤波电路和直流稳压电源电路,其难点在于相敏整流电路的设计。信号调理模块的主要功能是把输入的交流信号X=AsinOcosor、Y=Acosθcosot转变成直流信号Bsinθ和Bcosθ,并使输出的直流信号在0~2.4V之间;系统芯片C8051F064是CYGNAL公司近年来推出的一款功能齐全的完全集成的混合信号片上系统型单片机。在本文所设计的系统中,系统芯片的输入信号为直流信号Bsinθ和Bcosθ,通过片内自带的2个16位A/D转换器对输入信号的数据进行采样和转换,并对转换完的数据进行滤波处理,以减小由于外界干扰而产生的误差,再用除法和反正切函数解算出偏转角θ的16位数字量;输出控制模块主要完成的功能是通过UARTO向计算机实时发送由单片机计算出来的偏转角度0的16位数字量,而串口的RS-232电平与单片机系统采用的是TTL电平之间的转换所采用的转换芯片是MC1488和MC1489。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值