2022.3.6
Codeforces Round #775 (Div. 2) A-C
A. Game
题意:给你一个01序列,1代表陆地0代表海洋,相邻的陆地可以走,对于海洋而言你有一次机会花费i+x个金币跳到任意陆地x,问最小花费
找到第一个0和最后一个0,计算一下花费即可,特判一下全是陆地的情况。
感想:一开始读题读错了,以为是可以无限制跳,得注意
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e2+10,INF=1e8;
int a[N];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n,f=1;
scanf("%d", &n);
for (int i = 1; i <= n;i++)
{
scanf("%d", &a[i]);
if(a[i]==0)
f = 0;
}
if(n==2||f)
printf("0\n");
else
{
int ans = 0;
int x = 0, y = 0;
for (int i = 1; i <= n;i++)
{
if(a[i]==0)
{
x = i;
break;
}
}
for (int i = n; i >= 1;i--)
{
if(a[i]==0)
{
y = i;
break;
}
}
if(x==y)
ans = 2;
else
ans = y + 2 - x;
printf("%d\n", ans);
}
}
return 0;
}
B. Game of Ball Passing
题意:有n个人在练习传球,给你长度为n的序列表示每个人传球的次数,确定他们最少用了几个球在练习传球
思路:排序一下,如果最大值大于前面所有值的和,说明1个球肯定是不能符合的,最少的球数即为a[n]-sum[n-1],如果a[n]<=sum[n-1]的话那一个球就够了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+10,INF=1e8;
int a[N];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n, cnt = 0,f=1;
scanf("%d", &n);
for (int i = 1; i <= n;i++)
{
scanf("%d", &a[i]);
if(a[i])
f = 0;
}
if(f)
{
printf("0\n");
continue;
}
sort(a + 1,a + 1 + n);
ll sum = 0;
for (int i = 1; i < n;i++)
sum += a[i];
if(a[n]<=sum)
printf("1\n");
else
printf("%d\n", a[n] - sum);
}
return 0;
}
C. Weird Sum
给你一个NxM的矩阵,要求求所有相同颜色的曼哈顿距离之和,用vector存一下分别相同颜色的点的x,y坐标,再将他们从小到大排序,累加起来。公式:(Vi*i-last) (0<i<k),公式推导画图理解一下。
记得得开long long
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1e5+50,INF=1e8;
int n,m;
vector<int> row[N], col[N];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n;i++)
for (int j = 1; j <= m;j++)
{
int x;
scanf("%d", &x);
row[x].push_back(i);
col[x].push_back(j);
}
ll ans = 0;
for (int i = 1; i < N;i++)
{
if(row[i].size())
{
ll cnt = 0, last = 0;
sort(row[i].begin(),row[i].end());
for(auto j:row[i])
{
ans += j * cnt - last;
cnt++, last += j;
}
}
if(col[i].size())
{
ll cnt1 = 0, last1 = 0;
sort(col[i].begin(),col[i].end());
for (auto j:col[i])
{
ans += j * cnt1 - last1;
cnt1++, last1 += j;
}
}
}
printf("%lld", ans);
return 0;
}
AtCoder Beginner Contest 242 A-D
A - T-shirt
有一群人,编号1-N,其中某一个人编号为X,在A和A之前的可以获得t恤,在A+1到B的人其中有C个可以获得t恤,给你A B C X,让你求出X获得t恤的概率。
读太快看漏了,以为是A到B其中的人有C个
double a, b, c, x;
scanf("%lf%lf%lf%lf", &a,&b,&c,&x);
double ans = 0;
if(x<=a)
{
ans = 1;
}
else if(x>a&&x<=b)
{
ans = c / (b - a);
}
else
ans = 0;
printf("%.12lf",ans);
return 0;
B - Minimize Ordering
给你一个字符串,输出字典序最小的串
sort
scanf("%s", s);
int str = strlen(s);
sort(s, s + str);
puts(s);
return 0;
C - 1111gal password
给你一个数N,找出N位数里有多少个数满足:相邻两位绝对值<=1,且每一位数在1-9之间。
思路:dp[i][j],i表示当前一共有几位数,j表示该数的第一个数,对于i,j,可以发现dp[i][j]=dp[i][j]+dp[i][k] (max(1,j-1)<=k<=min(9,j+1),即j-1到j+1都是相邻的数,所以可以填j。
当时以为是找规律,感觉有点像dp,看完题解发现确实是dp。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e6+10,INF=1e8,mod=998244353;
int dp[N][10];
int main()
{
for (int i = 1; i <= 9;i++)
dp[0][i] = 1;//初始化一下,因为a[1][j]=1
int n;
scanf("%d", &n);
for (int i = 1; i < n;i++)
for (int j = 1; j <= 9;j++)
for (int k = max(1, j - 1); k <= min(9, j + 1);k++)
{
dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;
}
int ans = 0;
for (int i = 1; i <= 9;i++)
ans = (ans + dp[n - 1][i]) % mod;//所有数加起来就是n位数时满足的解
printf("%d\n", ans);
return 0;
}
D - ABC Transform
给你一个由A,B,C组成的字符串s0,每次字符串迭代的时候A->BC,B->CA,C->AB,其中A的第1个后继为B,第2个后继为C...有n个询问,每次输入两个数,t,k,输出st的第k个字母
思路:递归,由于s从0开始数,k从1开始数,对齐一下t,k 先让k--,发现字符串每次迭代长度都是乘2的,当k=0的时候就是让你求原字符串的第一个字母迭代t次之后是什么字母,可以发现ABC周期是3,于是只需要返回(s[0]+t)%3即可,当t=0的时候就是原字符串的第k个字符,返回s[k]-'A'。当t,k都不为0时,观察一下,如果当前k是偶数的话,那么它是(t-1,k/2)字母的第一个后继,如果k是奇数的话,那么它是(t-1,k/2)的字母的第二个后继。于是综合一下,对于t,k,返回((t-1,k/2)+k%2+1)%3。如果k是偶数的话那么k%2=0再+1说明它是(t-1,k/2)字母的第一个后继,同理k为奇数它是第二个后继。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e5+10,INF=1e8;
char s[N];
int get(ll t,ll k)
{
if(t==0)
return s[k] - 'A';
else if(k==0)
return (s[0] - 'A' + t) % 3;
else
return (get(t - 1, k / 2) + k % 2 + 1) % 3;
}
int main()
{
scanf("%s", &s);
int n;
scanf("%d", &n);
while(n--)
{
ll t, k;
scanf("%lld%lld", &t, &k);
k--;
printf("%c\n", 'A' + get(t, k));
}
return 0;
}
蓝书
AcWing 98. 分形之城
首先我们得观察一下图形,我们发现第n级的左上角是由n-1级的图形顺时针旋转90度的得到的,右上角则是直接平移,右下角是由右上角向下平移得到,左下角则是逆时针旋转90度再向下平移2倍n=1的长度再-1得到的,其他三个比较好理解但对于左下角还是需要了解一下矩阵的旋转平移啥的。观察发现每一级的边长其实就是2n,城市的个数则是4n,我们可以把当前一级的城市看成是由4个n-1级城市组成的,如果要确定两个城市的距离的话得先确定他们分别位于哪个城市最后通过递归取得城市的坐标,最后计算距离。
最开始做这一题的时候畏难情绪很强,后面要再反复回顾。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
const int N=1e5+10,INF=1e8;
double dist(PLL a,PLL b)
{
return sqrt((a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second));
}
PLL get(ll n,ll x)
{
if(n==0)
return {0, 0};
ll len = pow(2,n-1), cnt = pow(4,n-1);
PLL pos = get(n - 1, x % cnt);
ll xx = pos.first, yy = pos.second;
ll z = x / cnt;
if(z==0)
return {yy, xx};
if(z==1)
return {xx, yy + len};
if(z==2)
return {xx + len, yy + len};
return {2 * len - yy - 1, len - xx - 1};
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
ll n,a,b;
scanf("%lld%lld%lld", &n, &a, &b);
a--, b--;
PLL ans1 = get(n, a);
PLL ans2 = get(n, b);
printf("%.lf\n", dist(ans1, ans2)*10);
}
return 0;
}