当前位置:网站首页>NIO‘s Sword(思维,取模,推公式)
NIO‘s Sword(思维,取模,推公式)
2022-08-01 10:32:00 【小酒窝.】
NIO’s Sword
题意
一共有 n 个怪兽,有一把初始能量为 0 的宝剑。
每次可以在某一时刻将宝剑的能量升级:如果原来能量为 a a a,升级之后能量变为 a ∗ 10 + x a*10 + x a∗10+x,x 为 0 − 9 0-9 0−9 中任选的一个数。
如果想要击败第 i ( 2 ≤ i ≤ n ) i\ (2\le i\le n) i (2≤i≤n) 只怪兽,需要保证第 i − 1 i-1 i−1 只怪兽已经被击败。
在击败第 i 只怪兽时,宝剑的能量 a 需满足 A ≡ i ( m o d n ) . A≡i\ (\bmod\ n). A≡i (mod n).
问,击败所有怪兽最少需要升级多少次?
1 ≤ n ≤ 1 0 6 1\le n\le 10^{6} 1≤n≤106
思路
如果击败第 i 个怪兽时,宝剑的能量值为 a,并且 a%n = i,而要击败第 i+1 个怪兽是由 a 继续升级的,也就是由 i 继续升级,所以就是看将值 i 升级到 t 满足 t%n = (i+1)%n 最少需要升级多少次。
升级 1 次后的能量为: a ∗ 10 + x a*10 + x a∗10+x,x 属于 [ 0 , 9 ] [0, 9] [0,9];
升级 2 次后的能量为: a ∗ 1 0 2 + x a*10^2 + x a∗102+x,x 属于 [ 0 , 99 ] [0, 99] [0,99];
…
升级 k 次的能量为: a ∗ 1 0 k + x a*10^k + x a∗10k+x,x 属于 [ 0 , 1 0 k − 1 ] [0, 10^k-1] [0,10k−1];
要使得: ( a ∗ 1 0 k + x ) m o d n = b m o d n (a*10^k + x)\bmod n = b \bmod n (a∗10k+x)modn=bmodn
- 如果 a ∗ 1 0 k ( m o d n ) ≤ b ( m o d n ) a*10^k(\bmod n) \le b (\bmod n) a∗10k(modn)≤b(modn) 时, x = b ( m o d n ) − a ∗ 1 0 k ( m o d n ) x = b(\bmod n)-a*10^k(\bmod n) x=b(modn)−a∗10k(modn);
- 否则, ( a ∗ 1 0 k + x ) m o d n (a*10^k + x)\bmod n (a∗10k+x)modn 就应该变为 b ( m o d n ) + n b(\bmod n)+n b(modn)+n,要使得 x 尽可能小,那么 x = n + b ( m o d n ) − a ∗ 1 0 k ( m o d n ) x = n+b (\bmod n)-a*10^k(\bmod n) x=n+b(modn)−a∗10k(modn)
如果 x 在这次升级所能达到的范围内的话,说明就是这次升级就是满足的。
而 n 最大到 1e6,那么 x 最多 6 次就可以构造出任意小于 n 的值,所以最多升级 6 次,暴力枚举每次升级。
最后注意当 n 为 1 时,任意能量值 a 都同余于 1%1,所以能量值为0也行,不需要升级,注意特判。
Code
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define int long long
const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];
int pd(int a, int b)
{
int k = 0;
while(1)
{
k ++;
a = a*10 % n;
int x;
if(a <= b) x = b - a;
else x = n + b - a;
if(x <= pow(10, k)-1) break;
}
return k;
}
signed main(){
Ios;
cin >> n;
if(n == 1){
cout << 0; return 0;
}
int ans = 0;
for(int i=0;i<n;i++)
{
ans += pd(i, (i+1)%n);
}
cout << ans;
return 0;
}
经验
这样的取模的式子一直不会化,总觉得取模之后原来的数就变的面目全非了,然后就不敢往下化,怕不等。
其实取模在乘法和加法运算时和原式是毫无影响的,该咋化就咋化,不用怕。
感谢队友大半夜教会我!!
Jobs (Easy Version)
题意
给定 n 个集合,每个集合有 mi 个三元组 { x j , y j , z j x_j, y_j, z_j xj,yj,zj}。
一共 q 次询问,每次询问给定一个三元组 {a, b, c},问一共有多少个集合满足,其中存在一个三元组,其三个元素都不超过 {a, b, c}?
1 ≤ n ≤ 10 , 1 ≤ q ≤ 2 × 1 0 6 , 1 ≤ x j , y j , z j ≤ 400 1 \le n \le 10,\ 1 \le q \le 2\times 10^6,\ 1 \le x_j,y_j,z_j \le 400 1≤n≤10, 1≤q≤2×106, 1≤xj,yj,zj≤400
思路
一共 1e6 次询问,每次询问要处理 10 个集合,那么留给每个集合的计算时间就很少了,暴力枚举不行。
一种非常巧妙的思路是,构造二维前缀最小值。
对于三元组{x, y, z},可以将矩阵 (x, y) 位置上的值 f[x, y] 置为 z。
最后将 f[][] 数组更新成前缀最小值,即 (1,1) 位置到 (x, y) 位置的所有位置中,z 的最小值。
后面对于每次询问 {a, b, c},肯定要从 (1, 1) 到 (a, b) 位置中找到最小值,即 f[a, b],判断其和 c 的大小关系。如果最小值不超过 c,则说明存在某个位置 (x, y),其值 z = f[x, y] 不超过 c,即找到满足三元组。
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
const int N = 200010, mod = 998244353;
int T, n, m;
int a[N];
int f[11][410][410];
int solve(int x, int y, int z)
{
int cnt = 0;
for(int i=1;i<=n;i++)
{
if(f[i][x][y] <= z) cnt++;
}
return cnt;
}
int qmi(int x, int y)
{
int ans = 1;
while(y)
{
if(y & 1) ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
signed main(){
Ios;
cin >> n >> m;
for(int i=0;i<=n;i++)
for(int j=0;j<=400;j++)
for(int k=0;k<=400;k++)
f[i][j][k] = 1e9;
for(int i=1;i<=n;i++)
{
int k; cin >> k;
while(k--)
{
int x, y, z; cin >> x >> y >> z;
f[i][x][y] = min(f[i][x][y], z);
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=400;j++){
for(int k=1;k<=400;k++)
{
f[i][j][k] = min(f[i][j][k], f[i][j-1][k]);
f[i][j][k] = min(f[i][j][k], f[i][j][k-1]);
}
}
}
int seed;
cin >> seed;
std::mt19937 rng(seed);
std::uniform_int_distribution<> u(1,400);
int lastans=0, ans = 0;
for (int i=1;i<=m;i++)
{
int IQ=(u(rng)^lastans)%400+1; // The IQ of the i-th friend
int EQ=(u(rng)^lastans)%400+1; // The EQ of the i-th friend
int AQ=(u(rng)^lastans)%400+1; // The AQ of the i-th friend
lastans=solve(IQ,EQ,AQ); // The answer to the i-th friend
ans = (ans + lastans * qmi(seed, m-i) % mod) % mod;
}
cout << ans;
return 0;
}
还有一种比较巧妙的思路:
类似于单调栈,如果对于当前三元组 {x, y, z},发现集合中存在一个三元组{a, b, c}满足,其三个元素都比当前三元组的三个元素小,那么当每次询问的时候,只需要判断最小值是否满足,那么当前三元组 {x, y, z} 就没有存在的意义,完全可以删掉。
所以可以先按照三元素大小将集合中三元组从小到大排序,维护一个vector表示最后剩下的三元组,遍历所有三元组,如果对于当前三元组发现vector中存在一个三元组比当前优,那么当前的就不要了,否则就加到vector里。
这样删过之后,对于三个位置,要么有比它大的,要么有比它小的,最多只有 8 个三元组了,然后每次询问遍历每个集合的 8 个三元组即可。
这样的话完全不用考虑每个元素的大小。
#include<bits/stdc++.h>
using namespace std;
#define Ios ios::sync_with_stdio(false),cin.tie(0)
const int N = 200010, mod = 998244353;
int T, n, m;
struct node{
int x, y, z;
};
vector<node> a[12], v[12];
bool cmp(node a, node b){
if(a.x != b.x) return a.x < b.x;
else if(a.y != b.y) return a.y < b.y;
return a.z < b.z;
}
int solve(int x, int y, int z)
{
int cnt = 0;
for(int i=1;i<=n;i++)
{
for(node t : v[i])
{
if(t.x <= x && t.y <= y && t.z <= z){
cnt ++;
break;
}
}
}
return cnt;
}
int qmi(int x, int y)
{
int ans = 1;
while(y)
{
if(y & 1) ans = ans * x % mod;
x = x * x % mod;
y >>= 1;
}
return ans;
}
signed main(){
Ios;
cin >> n >> m;
for(int i=1;i<=n;i++)
{
int k; cin >> k;
while(k--)
{
int x, y, z; cin >> x >> y >> z;
a[i].push_back({
x, y, z});
}
}
for(int i=1;i<=n;i++)
{
sort(a[i].begin(), a[i].end(), cmp);
for(node t : a[i])
{
int flag = 0;
for(node left : v[i])
{
if(left.x <= t.x && left.y <= t.y && left.z <= t.z) flag = 1;
}
if(!flag) v[i].push_back(t);
}
}
int seed;
cin >> seed;
std::mt19937 rng(seed);
std::uniform_int_distribution<> u(1,400);
int lastans=0, ans = 0;
for (int i=1;i<=m;i++)
{
int IQ=(u(rng)^lastans)%400+1; // The IQ of the i-th friend
int EQ=(u(rng)^lastans)%400+1; // The EQ of the i-th friend
int AQ=(u(rng)^lastans)%400+1; // The AQ of the i-th friend
lastans=solve(IQ,EQ,AQ); // The answer to the i-th friend
ans = (ans + lastans * qmi(seed, m-i) % mod) % mod;
}
cout << ans;
return 0;
}
感谢友队提供思路,很强!
边栏推荐
- 线上问题排查常用命令,总结太全了,建议收藏!!
- 开天aPaaS之移动手机号码空号检测【开天aPaaS大作战】
- C语言实现!20000用4秒计算
- 深度学习 | MATLAB实现一维卷积神经网络convolution1dLayer参数设定
- 招聘随想2022
- 可视化——Superset安装与部署
- MFC implementation road map navigation system
- 已解决(pip安装库报错)Consider using the-- user option or check the permissions.
- Mini Program Graduation Works WeChat Food Recipes Mini Program Graduation Design Finished Products (4) Opening Report
- 世界第4疯狂的科学家,在103岁生日那天去世了
猜你喜欢

AI篮球裁判火了,走步算得特别准,就问哈登慌不慌

Py之yellowbrick:yellowbrick的简介、安装、使用方法之详细攻略

Batch大小不一定是2的n次幂!ML资深学者最新结论

Drawing arrows of WPF screenshot control (5) "Imitation WeChat"

ClickHouse多种安装方式

Why Metropolis–Hastings Works

CTFshow,命令执行:web33

PowerPC技术与市场杂谈

mysql login in cmd and basic operations of database and table

CTFshow,命令执行:web37
随机推荐
C#/VB.NET convert PPT or PPTX to image
编码解码(btoa、encodeURIComponent、encodeURI、escape)
How to find out hidden computer software (how to clean up the computer software hidden)
在线GC日志分析工具——GCeasy
Basic configuration commands of cisco switches (what is the save command of Huawei switches)
小程序毕设作品之微信美食菜谱小程序毕业设计成品(3)后台功能
shell--面试题
What is a stepper motor?40 pictures to show you!
回归预测 | MATLAB实现TPA-LSTM(时间注意力注意力机制长短期记忆神经网络)多输入单输出
Introduction to data warehouse layering (real-time data warehouse architecture)
redis
STM32入门开发 介绍IIC总线、读写AT24C02(EEPROM)(采用模拟时序)
Drawing arrows of WPF screenshot control (5) "Imitation WeChat"
CTFshow,命令执行:web34、35、36
【无标题】
Promise学习(四)异步编程的终极解决方案async + await:用同步的方式去写异步代码
使用ESP32驱动QMA7981读取三轴加速度(带例程)
Android 安全与防护策略
Endorsed in 2022 years inventory | product base, science and technology, guangzhou automobile group striding forward
RK3399平台开发系列讲解(内核入门篇)1.52、printk函数分析 - 其函数调用时候会关闭中断