2021牛客寒假算法基础集训营6 ACDFGIJ
A. 回文括号序列计数
坑比题...注意回文的定义,并不是括号序列对称。比如(())不是回文的而))是回文的。而合法括号列左右两端一定是(和),必然非回文,因此只有空串答案是1.
#include <iostream>
using namespace std;
#define mod 998244353
int n;
int main()
{
//freopen("data.txt", "r", stdin);
int t;
cin >> t;
while(t--)
{
cin >> n;
if(!n) cout << 1 << endl;
else cout << 0 << endl;
}
return 0;
}
C. 末三位
快速幂会t,因此可以找规律。
证明详见https://blog.nowcoder.net/n/caa12c854288451a9bf1288a291a8e15
#include <iostream>
using namespace std;
int n;
int main()
{
freopen("data.txt", "r", stdin);
while(cin >> n)
{
if(n == 0) cout << "001" << endl;
else if(n == 1) cout << "005" << endl;
else if(n == 2) cout << "025" << endl;
else if(n == 3) cout << "125" << endl;
else if(n == 4) cout << "625" << endl;
else if(n & 1) cout << "125" << endl;
else cout << "625" << endl;
}
return 0;
}
D. 划数
“已知其中一个数cnt(cnt >= 11)”,而两数相加对11取模后肯定小于11,因此这肯定是数列的一个原本的数,那么剩下另一个数就是原来序列其他数的和。根据取模运算律直接计算即可。注意n = 2要特判。
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int n, cnt, a[150005], sum = 0;
int main()
{
freopen("data.txt", "r", stdin);
while(cin >> n >> cnt)
{
sum = 0;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
sum = (sum + a[i]) % 11;
}
if(n == 2)
{
if(cnt == a[1]) cout << a[2] << endl;
else cout << a[1] << endl;
continue;
}
cout << (sum - cnt % 11 + 11) % 11 << endl;//cnt >= 11 肯定是数列的一个数 那么输出的就是剩下部分的和
}
return 0;
}
F. 组合数问题
打表找规律可以解决,发现每次都是2的次幂附近的数,这些数与最近的2的次幂作差的绝对值又恰好是等比数列...
证明见官方题解https://ac.nowcoder.com/discuss/599236?type=101&order=0&pos=1&page=1&channel=-1&source_id=1或者大佬博客https://blog.nowcoder.net/n/4682f520b038471dab543ab91c197727。
#include <iostream>
#define p 998244353
#define LL long long
#define maxn 100005
using namespace std;
void extend_gcd(LL a,LL b,LL &x,LL &y){
if(b==0){
x=1,y=0;
return;
}
extend_gcd(b,a%b,y,x);
y-=a/b*x;
}
LL inv[maxn + 10];
LL f[maxn+10];
void init(){//阶乘及其逆元打表
f[0]=1;
for(int i=1;i<=maxn;i++){
f[i]=f[i-1]*i%p;
}
LL x,y;
extend_gcd(f[maxn],p,x,y);//先求出f[N]的逆元,再循环求出f[1~N-1]的逆元
inv[maxn]=(x%p+p)%p;
for(int i=maxn-1;i>=1;i--){
inv[i]=inv[i+1]*(i+1)%p;
}
}
LL C(LL n,LL m){
if(n==m||m==0)return 1;
return (f[n]*inv[m]%p*inv[n-m]%p)%p;
}
long long fpow(long long a, long long b)
{
long long ans = 1;
for(; b; b >>= 1)
{
if(b & 1) ans = ans * a % p;
a = a * a % p;
}
return ans;
}
int main()
{
//init();
// int n = 4;
// LL ans = 0;
// for(int i = 0; i <= n; i += 4)
// {
// ans = (ans + C(n * 1ll, i * 1ll)) % p;
// }
// cout << ans;
freopen("data.txt", "r", stdin);
long long n;
cin >> n;
cout << (fpow(2, n - 2) + p + ((n / 4) & 1 ? -1 : 1) * 2 * fpow(4, n / 4 - 1) % p) % p;
return 0;
}
G. 机器人
全排列会t(因为没法剪枝),考虑贪心:
两个机器人时:\(a_1(a_2x+b_2)+b_1<a_2(a_1x+b_1)+b_2\),可以推广到多个,因此按照这个策略排序后计算答案即可。
答案会爆long long,因此用__int128存储(or 高精度 or 两个long long)
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
int n;
__int128 x;
bool vis[25];
long long ans = 0;
struct robot
{
long long a, b;
} r[25];
bool cmp(robot x, robot y)
{
//return (x.a - 1) * 1.0 / x.b < (y.a - 1) * 1.0 / y.b;
return x.b + x.a * y.b < y.b + y.a * x.b;
}
char ibuf[1000050],*s=ibuf;
inline __int128 read()
{
__int128 x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void write(__int128 x)
{
if(x<0)
{
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
int main()
{
freopen("data.txt", "r", stdin);
cin >> n;
x = read();
for(int i = 1; i <= n; i++)
{
cin >> r[i].a >> r[i].b;
}
sort(r + 1, r + n + 1, cmp);
for(int i = 1; i <= n; i++)
{
x = x * r[i].a + r[i].b;
}
write(x);
return 0;
}
I. 贪吃蛇
注意到尾巴不缩回,实际上就是BFS.
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int n, m;
char mmap[105][105];
bool vis[105][105];
struct node
{
int x, y, len;
};
node s, t;
int ans = 0x3f3f3f3f;
int dir[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
void bfs()
{
queue<node> q;
q.push(s);
while(q.size())
{
node now = q.front();
q.pop();
//cout << now.x << ' ' << now.y << endl;
if(now.x == t.x && now.y == t.y)
{
ans = now.len;
break;
}
for(int i = 0; i < 4; i++)
{
int nx = now.x + dir[i][0], ny = now.y + dir[i][1];
if(!vis[nx][ny] && nx >= 1 && nx <= n && ny >= 1 && ny <= m)
{
vis[nx][ny] = 1;
node nxt;
nxt.x = nx, nxt.y = ny, nxt.len = now.len + 1;
q.push(nxt);
}
}
}
}
int main()
{
//freopen("data.txt", "r", stdin);
memset(vis, 0, sizeof(vis));
cin >> n >> m;
cin >> s.x >> s.y >> t.x >> t.y;
s.len = 0;
for(int i = 1; i <= n; i++)
{
scanf("%s", mmap[i] + 1);
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(mmap[i][j] == '#')
{
vis[i][j] = 1;
}
}
}
vis[s.x][s.y] = 1;
bfs();
if(ans != 0x3f3f3f3f) cout << ans * 100;
else cout << -1;
return 0;
}
J. 天空之城
观察到走过的路代价为0,就是裸的MST。
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
#define mod 998244353
int n, q, city = 0;
struct edge
{
int x, y, z;
};
bool cmp(edge a, edge b)
{
return a.z < b.z;
}
int fa[5005];
int get(int x)
{
if(x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
int main()
{
//freopen("data.txt", "r", stdin);
while(cin >> n >> q)
{
vector<edge> v;
for(int i = 1; i <= n; i++) fa[i] = i;
map<string, int> mp;
city = 0;
string tmp;
cin >> tmp;
mp[tmp] = ++city;
int cnt = 0;
for(int i = 1; i <= q; i++)
{
string uu, vv;
int x, y, w;
cin >> uu >> vv >> w;
if(mp.find(uu) != mp.end())
{
x = mp[uu];
}
else x = mp[uu] = ++city;
if(mp.find(vv) != mp.end())
{
y = mp[vv];
}
else y = mp[vv] = ++city;
edge ee;
ee.x = x, ee.y = y, ee.z = w;
v.push_back(ee);
}
sort(v.begin(), v.end(), cmp);
long long ans = 0;
for(int i = 0; i < v.size(); i++)
{
if(cnt == n - 1) break;
int x = v[i].x, y = v[i].y;
int xx = get(x), yy = get(y);
if(xx == yy) continue;
ans += 1ll * v[i].z;
fa[xx] = yy;
cnt++;
}
if(cnt == n - 1) cout << ans << endl;
else cout << "No!" << endl;
}
}