A-AFei Loves Magic
思路:如果两个魔法石相遇,需要改变各自的方向并且以和原来相同的速度前进。这是和魔法石在同一地方相遇,但是方向不变,继续运动是等价的。因此只需算出t时间后还有多少,魔法石在(0,L)中即可。
代码
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int x, d;
int n, L, t;
int main()
{
cin >> n >> L >> t;
int res = 0;
for (int i = 0; i < n; i ++)
{
cin >> x >> d;
if (d == 1 && x >= L - t) res ++;
if (d == 2 && x - t <= 0) res ++;
}
cout << n + 1 - res;
}
B - bearBaby loves sleeping
裸BFS,算出两点间最短距离
#include <iostream>
#include <cstring>
using namespace std;
typedef pair<int, int> PII;
#define x first
#define y second
const int N = 110;
int w[N][N];
int dist[N][N];
PII q[N * N];
int n, m, ex, ey;
int dx[4] = {-1 ,0, 1, 0};
int dy[4] = {0, 1, 0, -1};
int main()
{
cin >> n >> m;
cin >> ex >> ey;
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
cin >> w[i][j];
int hh = 0, tt = 0;
q[0] = {1, 1}, dist[1][1] = 0;
while (hh <= tt)
{
auto t = q[hh ++];
int tx = t.x, ty = t.y;
if (tx == ex && ty == ey)
{
cout << dist[tx][ty];
return 0;
}
for (int i = 0; i < 4; i ++)
for (int j = 0; j < 4; j ++)
{
int sx = tx + dx[i];
int sy = ty + dy[i];
if (sx <= 0 || sx > n || sy <= 0 || sy > m || w[sx][sy] || dist[sx][sy]) continue;
dist[sx][sy] = dist[tx][ty] + 1;
q[++ tt] = {sx, sy};
}
}
}
C-Sleepy Kaguya
通过前几项可以猜测:如果n是负数,则输出-1,否则是1。
如果需要证明,可以通过数学归纳法。
代码
#include <iostream>
using namespace std;
int main()
{
long long n;
cin >> n;
if (n & 1) cout << -1;
else cout << 1;
}
D-Dandan’s lunch
根据作出的题目量,得到相应数量的蛋糕数。难点是怎么求出蛋糕数(即三角形的面积)
我运用了海伦公式
公式描述:公式中a,b,c分别为三角形三边长,p为半周长,S为三角形的面积。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef pair<int ,int> PII;
const int N = 1e5 + 10;
PII person[N];
double tri[N];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i ++)
{
int num;
double x1, y1, x2, y2, x3, y3;
cin >> num >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
person[i] = {num, i};
double a = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
double b = sqrt((x3 - x1) * (x3 - x1) + (y3 - y1) * (y3 - y1));
double c = sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2 - y3));
double p = (a + b + c) / 2;
double s = 2 * sqrt(p * (p - a) * (p - b) * (p - c));
tri[i] = s;
}
sort(tri, tri + n);
sort(person, person + n);
for (int i = 0; i < n; i ++)
{
if (person[i].second == 0)
cout << (long long)(tri[i] + 0.5);
}
}
E-Easy problem
找出x的倍数,要求找出的倍数包含所有题目要求的数字。
一开始我理解错了,以为找出的倍数只能是要求的数字且所有数字都要使用,所以卡了很久。
注意 1<=x<=1e8, y <= 1e18
可以设y = 123456789000000000。
①如果y是x的倍数,直接输出。
②如果不是,调整y的值,y % x是多出来的值,因此在y的基础上再加上x - y % x,y即是x的倍数。又因为x是1e8范围内的数,所以y改变只改变低位的值,变为1234567890XXXXXXXX。
代码
#include <iostream>
using namespace std;
int main()
{
int t;
cin >> t;
while (t --)
{
long long n = 123456789000000000;
int x, k;
cin >> x >> k;
while (k --)
{
int mm;
cin >> mm;
}
if (x % n) cout << n + (x - n % x) << endl;
else
cout << n;
}
}
F-Find the AFei Numbers
数位DP
似乎做麻烦了,等看了题解再改
(似乎可以f[i][j], j记录两位数]
#include <iostream>
#include <vector>
using namespace std;
const int N = 20;
long long f[N][10];
long long tens[N];
void init()
{
tens[0] = 1;
for (int i = 1; i < N; i ++)
tens[i] = tens[i - 1] * 10;
for (int i = 1; i < N; i ++)
for (int j = 0; j <= 9; j ++)
{
if (j == 5)
{
if (i - 3 >= 0)
{
f[i][j] += tens[i - 3];
for (int k = 1; k <= 9; k ++)
f[i][j] += f[i - 2][k];
for (int k = 0; k <= 9; k ++)
if (k != 2)
f[i][j] += f[i - 1][k];
}
}
else
for (int k = 0; k <= 9; k ++)
f[i][j] += f[i - 1][k];
}
}
int main()
{
init();
int t;
cin >> t;
while (t --)
{
long long n;
cin >> n;
long long res = 0;
vector<int> nums;
while (n)
{
nums.push_back(n % 10);
n /= 10;
}
int last0 = -1;
int last1 = -1;
int last2 = -1;
for (int i = nums.size() - 1; i >= 0; i --)
{
int flag = 0;
int x = nums[i];
for (int j = 0; j < x; j ++)
{
if (last2 == 5 && j == 2)
{
if (i > 0)
res += tens[i - 1];
for (int k = 1; k <= 9; k ++)
res += f[i][k];
}
else if (last1 == 5 && last2 == 2 && j == 0)
{
res += tens[i];
}
else
res += f[i + 1][j];
}
last0 = last1;
last1 = last2;
last2 = x;
if (last0 == 5 && last1 == 2 && last2 == 0)
{
long long num = 0;
for (int k = i - 1; k >= 0; k --)
{
num *= 10;
num += nums[k];
}
num ++;
res += num;
flag = 1;
break;
}
if (flag)
break;
}
cout << res << endl;
}
}
H - Kuangyeye and hamburgers
排序后求前缀和即可
s[n] = w[1]+w[2] … + w[n]
w[a]+w[a + 1]…+w[b] = s[b] - s[a - 1]
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
int w[N], s[N];
int n, k;
typedef long long LL;
int main()
{
cin >> n >> k;
for (int i = 1; i <= n; i ++)
{
cin >> w[i];
}
sort(w + 1, w + n + 1, greater<int>());
for (int i = 1; i <= n; i ++)
{
s[i] = s[i - 1] + w[i];
}
LL res = -1;
for (int i = 0; i < k; i ++)
{
int a, b;
cin >> a >> b;
res = max(res, (LL)s[b] - s[a - 1]);
}
cout << res;
}
I - II play with GG
博弈论
需要用到SG函数的知识
SG[x][y] = mex(SG[x -1][y], SG[x][y], SG[x][y-1])
最后算出起点的SG值,如果是0,则gg赢,否则II赢
#include <iostream>
#include <unordered_set>
#include <cstring>
using namespace std;
const int N = 1010;
int sg[N][N];
int x, y;
int dx[3] = {-1, -1, 0};
int dy[3] = {0, -1, -1};
int dfs(int x, int y)
{
unordered_set<int> st;
if (sg[x][y] != -1) return sg[x][y];
for (int i = 0; i < 3; i ++)
{
int ex = x + dx[i];
int ey = y + dy[i];
if (ex < 0 || ey < 0) continue;
st.insert(dfs(ex, ey));
}
for (int i = 0; ;i ++)
if (!st.count(i))
return sg[x][y] = i;
}
int main()
{
memset(sg, -1, sizeof sg);
cin >> x >> y;
dfs(x, y);
if (sg[x][y] == 0)
cout << "gg";
else
cout << "ii";
}
J - Less taolu
用数组记录状态避免重复搜索
#include<iostream>
using namespace std;
const long long mod = 1e9+7;
int f[100010];
long long func(int x){
if (f[x])
return f[x];
if (x==1||x==0){
return 1;
}
return f[x] = (x*func(x-1)+(x-1)*func(x-2))%mod;
}
int n;
int main(){
cin>>n;
cout<<func(n);
return 0;
}
L - The Right-angled Triangles
双指针
考虑若为直角三角形
则c^2 = a ^ 2 + b ^ 2
若直接枚举,显然会TLE。
所以先将[1,45000]的平方和存入数组中,对于输入的c,
设置双指针找到是否存在满足条件a ^ 2 + b ^ 2 = c ^ 2的值。时间复杂度为O(TC)
#include <iostream>
#include <cstring>
using namespace std;
const int N = 4e5 + 10;
int w[N];
int main()
{
for (int i = 1; i <= 45000; i ++)
w[i] = i * i;
int t, c;
cin >> t;
while (t --)
{
cin >> c;
c = c * c;
int l = 1, r = 45000;
bool flag = 0;
while (l <= r)
{
while (w[l] + w[r] < c)
l ++;
while (w[l] + w[r] > c)
r --;
if (w[l] + w[r] == c)
{
flag = 1;
break;
}
}
if (flag)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
L - The Digits String
矩阵快速幂+DP
设f[i][j]表示长度为i,i个数字的和模4为j的方案数
则f[i][0]可由f[i -1][0]序列后添0,4,8得。由f[i -1][1]序列后添3,7得。
由f[i -1][2]序列后添2,6得。由f[i -1][3]序列后添1,5,9得。
对其余三个状态同理
可得到状态转移方程
(f[i][0],f[i][1],f[i][2],f[i][3]) = (f[i - 1][0],f[i - 1][1],f[i - 1][2],f[i - 1][3]) * A
A为4 * 4矩阵
#include <iostream>
#include <cstring>
using namespace std;
const int mod = 2019;
void mul(int c[][4],int a[][4], int b[][4])
{
static int temp[4][4] = {0};
memset(temp, 0, sizeof temp);
for (int i = 0; i < 4; i ++)
for (int j = 0; j < 4; j ++)
for (int k = 0; k < 4; k ++)
temp[i][j] = (a[i][k] * b[k][j] + temp[i][j]) % mod;
memcpy(c, temp, sizeof temp);
}
int main()
{
int n;
while (cin >> n)
{
int f1[4][4] = {3, 3, 2, 2};
int a[4][4] = {
{3, 3, 2, 2},
{2, 3, 3, 2},
{2, 2, 3, 3},
{3, 2, 2, 3}
};
n --;
while (n)
{
if (n & 1) mul(f1, f1, a);
mul(a, a, a);
n = n >> 1;
}
cout << f1[0][0] << endl;
}
}
13届
L - Liao Han
题目描述:题目的意思是给定一个正整数n,求1-n中,约数个数为奇数的数的个数。
唯一分解定理,任意正整数n可分解为
其中p为质数。
从而可以得到N的约数个数为
一个数的约数个数为奇数,才是符合题目要求的,可以某个数满足题目要求和该数字是完全平方数是等价的。
①如果该数满足要求,则其所有a必然是偶数,因此是一个完全平方数。
②如果该数是一个完全平方数,则经过分解后,其指数(即a)必然是2的倍数,约数个数是奇数。
因此只要算出1-n中有几个完全平方数,即sqrt(n)。