官网链接
C 迷宫
题目描述
小王最近迷上了一款走迷宫游戏,这款走迷宫游戏在一个三维空间中运行,玩家在迷宫中可以通过操作手柄,每次进行上、下、左、右、前、后6个方向的移动。游戏进行过程中会出现以下两种操作中的一种:
1 x y z在迷宫的位置C(x,y,z)开放一个新的出口(原有的出口依然可用)。
2 x y z玩家出现在这个迷宫的位置Q(x,y,z)处。
对于每次操作2,玩家需要通过操作最少次数的手柄去到达一个出口,离开迷宫,输出此时的最少操作次数。
(保证第一次操作一定是操作1,也就是保证一定有出口)
输入描述:
给定一个t,代表t组测试数据。(1<=t<=12)
每组测试数据在一行给定一个n,m,h,q。(1<=n * m * h<=1e5,∑n * m * h<=5e5,1<=q<=1e5)
接下来q行,每行给定op,x,y,z。(1<=op<=2,1<=x<=n,1<=y<=m,1<=z<=h)
输出描述:
每组测试数据,针对每个操作2,输出最少操作手柄的次数。
示例一:
输入:
1
5 5 5 5
1 3 3 3
2 3 3 2
1 2 2 2
2 1 1 1
2 5 4 3
输出:
1
3
3
方法一(正解):
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'//用了这个替换,时间从400多ms提升到了100多ms!
#define please return
#define ac 0
typedef struct Node
{
int x,y,z;
} node;
void solve()
{
int n,m,h,Q;
cin >> n >> m >> h >> Q;
int dx[] = {-1,0,1,0,0,0},dy[] = {0,1,0,-1,0,0},dz[] = {0,0,0,0,1,-1};
// int dist[n + 5][m + 5][h + 5];//数组开到局部必须记得都初始化!
// memset(dist,0x3f,sizeof(dist));
vector<vector<vector<int>>> dist(n + 5,vector<vector<int>>(m + 5,vector<int>(h + 5)));//了解一下这种用法
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
for(int k = 1;k <= h;k++)
dist[i][j][k] = 0x3f3f3f3f;
queue<Node> q;
auto check = [&](Node a)->bool{
int x = a.x,y = a.y,z = a.z;
if(x > n || x < 1 || y > m || y < 1 || z > h || z < 1) return true;
else return false;
};
while (Q--)
{
int op,x,y,z;
cin >> op >> x >> y >> z;
if(op == 1)
{
dist[x][y][z] = 0;
q.push({x,y,z});
}
else
{
while (!q.empty())
{
auto t = q.front();
q.pop();
//从队列中的出口开始,宽搜目标点(x,y,z);
for (int i = 0; i < 6; i++)
{
int nx = dx[i] + t.x,ny = dy[i] + t.y,nz = dz[i] + t.z;
if(check({nx,ny,nz})) continue;
if(dist[nx][ny][nz] > dist[t.x][t.y][t.z] + 1)
{
dist[nx][ny][nz] = dist[t.x][t.y][t.z] + 1;
q.push({nx,ny,nz});
}
}
}
cout << dist[x][y][z] << endl;
}
}
return ;
}
signed main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T;
cin >> T;
while (T--)
{
solve();
}
please ac;
}
匿名函数的使用:
方法二(暴力):
(吐槽):
可以暴力过。但是很巧妙,起初我用的cin加速版搭配手写abs函数,再利用判断语句代替min函数,竟然AC了。之后全换上了scanf和printf竟然又不能过了,再换回cin和cout的加速也还是过不了,这也太神奇了吧。于是上网搜了下开氧气的代码,在牛客好像能用,但最好还是不要用。不过可以记住这行代码,毕竟有时候可能需要解决一些高复杂度的找规律题目,可以节省点时间,哈哈。
#pragma GCC optimize (2)//开氧气
#include<bits/stdc++.h>
using namespace std;
#define abs(x) ((x) < 0 ? -(x) : (x))
#define please return
#define ac 0
const int N = 1e5+10;
int a[3][N];
void solve()
{
int n,m,h,q;
int idx = 0;
cin >> n >> m >> h >> q;
while (q--)
{
int op,x,y,z;
cin >> op >> x >> y >> z;
if(op == 1)
{
a[0][idx] = x,a[1][idx] = y,a[2][idx++] = z;
}
else
{
int ans = 1e7;
for (int i = 0; i < idx; i++)
{
int t = abs(x - a[0][i]) + abs(y - a[1][i]) + abs(z - a[2][i]);
if(ans > t) ans = t;
}
printf("%d\n",ans);
}
}
return ;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T;
cin >> T;
while (T--)
{
solve();
}
please ac;
}
F gk的树
题目描述
jyq天天在公司摸鱼,感觉很无聊,突然想起了gk之前问过他的一个关于树的问题。
给你一颗树,每次操作你可以删掉一条边,最少需要多少次操作使得每个节点的度数都 <= k ?
输入描述:
第一行 T 表示一共有 T 组测试数据 (1≤T≤100000)
接下来一行输入给出的树的节点数 n 和度数限制 k (1 ≤ n,k ≤ 100000)
接下来 n−1 行输入相邻的两个节点 (u,v)。
Σn≤1e5
输出描述:
对于每一组测试数据输出最少的操作次数。
示例一:
输入:
2
4 2
1 2
2 3
2 4
6 2
1 2
1 3
1 4
4 5
4 6
输出:
1
1
说明:
第一组输入可以删掉 (1,2) 或 (2,3) 或 (2,4) 中的任意一条边。
第二组输入可以删掉 (1,4) 这条边。
#include<bits/stdc++.h>
using namespace std;
#define please return
#define ac 0
const int N = 1E5+10;
int h[N],e[N * 2],ne[N * 2],idx,d[N];//无向边
int n,k,res;
void add(int a,int b)
{
e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
void dfs(int u,int fa)
{
for(int i = h[u]; ~i;i = ne[i])
{
int j = e[i];
if(j == fa) continue;//因为是无向边,那么如果重复遍历,则直接continue
dfs(j,u);
}
if(d[u] > k)
{
res += d[u] - k;
d[fa] --;
}
}
void solve()
{
cin >> n >> k;
for (int i = 0; i < n - 1; i++)
{
int a,b;
cin >> a >> b;
add(a,b),add(b,a);//无向边
d[a]++,d[b]++;
}
int root = 0;
for(int i = 1;i <= n;i++)
if(d[root] < d[i]) root = i;//找到度数最大的点
res = 0;//初始化
dfs(root,0);
cout << res << endl;
return;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int T;
cin >> T;
while (T--)
{
memset(d,0,sizeof(d));//初始化
memset(h,-1,sizeof(h));//初始化
solve();
}
please ac;
}
J 大数乘法
题目描述
给定整数x,y,你需要输出 xy mod p 的值
输入描述:
第一行一个整数t(1 ≤ t ≤ 10),表示接下来有 t 组测试用例,每个测试用例有三行整数x,y,p。
0 ≤ x ≤ 100000,0 ≤ y ≤ 10100000,100000 ≤ p ≤ 1000000007
输出描述:
输出t行,每行一个整数代表xy mod p 的值。
示例1
输入
5
3
4
998244353
2
10
998244353
0
100
998244353
1
100
998244353
4
100
1000000007
输出
81
1024
0
1
499445072
备注:
00 = 1
题解:
知识点:欧拉降幂
b ≥ φ(m) 时,a b ≡ a(bmodφ(m))+φ(m) mod m
b < φ(m) 时,a b ≡ ab mod m
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define lowbit(x) ((x)&(-x))
#define fi first
#define se second
#define pb push_back
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c <= '9' && c >= '0') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
x *= f;
}
const int N = 1e5+10;
ll x,p;
char str[N];
ll fpow(ll a,ll b)
{
ll res = 1;
while (b)
{
if(b & 1) res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
ll get_euler(ll n)
{
ll res = n;
for (ll i = 2; i <= n / i; i++)
{
if(n % i == 0)
{
res = res / i * (i - 1);
while(n % i == 0) n /= i;
}
}
if(n > 1) res = res / n * (n - 1);
return res;
}
int main()
{
int t;
read(t);
while (t--)
{
scanf("%lld%s%lld",&x,str,&p);
ll phi = get_euler(p);
string s = str;
ll y = 0;
bool flag = false;
for (int i = 0; i < s.size(); i++)
{
y = y * 10 + s[i] - '0';
if(y >= phi)
{
y %= phi;
flag = true;
}
}
if(flag) y += phi;
printf("%lld\n",fpow(x,y));
}
return 0;
}