喜迎暑假多校联赛第一场
一、qcjj想玩 I wanna
传送门
不会不会,太难了,我是菜鸡 !
二、云哥教你学数学!
1.思路
拿到这题一看到n
≤
≤
≤
1
0
9
10^9
109,要求f(n),那肯定是矩阵快速幂的活了。
f
(
x
)
=
2
f
(
x
−
1
)
+
3
f
(
x
−
2
)
f(x)=2f(x-1)+3f(x-2)
f(x)=2f(x−1)+3f(x−2)
做过斐波拉契的矩阵快速幂的就能很快推出矩阵了,这个问题的矩阵就是
K
=
(
3
2
1
0
)
K= \begin{gathered} \begin{pmatrix} 3 & 2 \\ 1 & 0 \end{pmatrix} \end{gathered}
K=(3120)
所以最重要的一步还是求出f(1)和f(2),比赛时想破脑袋竟然没想到暴力bfs求,草率了!!!!!只需要暴力2,3,5,到1e31的时候就行。哎,还是太拉跨了。将暴力得到的符合条件的值放入set中,最后找出第a个和第b个即可。记得用__int128。
2.参考代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll M = 1e9 + 7;
void print(__int128 x)
{
if (!x) return;
if (x < 0) putchar('-'), x = -x;
print(x / 10);
putchar(x % 10 + '0');
}
struct Matrix
{
ll m[10][10];
Matrix()
{
memset(m, 0, sizeof(m));
}
};
ll ksc(ll a, ll b)
{
ll ans = 0;
while (b)
{
if (b & 1)ans = (ans + a) % M;
a = (a + a) % M;
b >>= 1;
}
return ans;
}
Matrix Multi(Matrix a, Matrix b)
{
Matrix res;
for (int i = 1; i <= 2; i++)
for (int j = 1; j <= 2; j++)
for (int k = 1; k <= 2; k++)
res.m[i][j] = (res.m[i][j] + ksc(a.m[i][k], b.m[k][j])) % M;
return res;
}
Matrix fastm(Matrix a, ll n)
{
Matrix res;
for (int i = 1; i <= 2; i++)
res.m[i][i] = 1;
while (n)
{
if (n & 1)res = Multi(res, a);
a = Multi(a, a);
n >>= 1;
}
return res;
}
set<__int128>ss;
void dfs(__int128 x)
{
if (x > 1e31 || ss.count(x) != 0)return;
ss.insert(x);
dfs(x * 2);
dfs(x * 3);
dfs(x * 5);
}
int main() {
dfs(1);
ll a, b, n;
scanf("%lld%lld%lld", &a, &b, &n);
Matrix k;
__int128 suma, sumb;
int flag = 1;
for (auto it : ss)
{
if (flag == a)suma = it;
if (flag == b)sumb = it;
flag++;
if (sumb != 0)break;
}
k.m[1][1] = 2;
k.m[1][2] = 3;
k.m[2][1] = 1;
k.m[2][2] = 0;
if (n == 1)
{
print(suma);
}
else
{
k = fastm(k, n - 2);
__int128 res = (sumb % M * k.m[1][1] + suma % M * k.m[1][2]) % M;
print(res);
}
}
三、纳米兔子
1.思路
没得思路,就是找规律,通过枚举前8种情况就行。我通过JAVA程序进行打表,得到了1到8代兔子数量积尾数0个数为1,2,4,8,15,25,35,35,到了这不就有手就行了。
2.参考代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll sum[] = { 0,1,2,4,8,15,25,35,35 };
int main()
{
ll n, m;
while (~scanf("%lld%lld", &n, &m))
{
printf("%lld\n", n * sum[m]);
}
}
四、纳米猫猫
1.思路
一样的没得思路,单纯就是找规律。
2.参考代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 123456;
int mod;
char s[N], b[N];
ll fastpower(ll x, ll y) {
ll ans = 1;
while (y)
{
if (y & 1) {
ans = (ans * x) % mod;
y--;
}
y /= 2;
x = x * x % mod;
}
return ans;
}
ll quickmod(ll a, char b[], int len)
{
ll ans = 1;
while (len > 0) {
if (b[len - 1] != '0') {
int s = b[len - 1] - '0';
ans = ans * fastpower(a, s) % mod;
}
a = fastpower(a, 10) % mod;
len--;
}
return ans;
}
int main() {
int a;
cin >> a >> s >> mod;
int len = strlen(s);
int i = len - 1;
while (s[i] == '0') {
s[i] = '9'; i--;
}
s[i]--;
i = 0;
while (s[i] == '0')i++;
for (int j = 0; s[i]; i++)b[j++] = s[i];
len = strlen(b);
if (mod == 1)cout << 0 << endl;
else
printf("%d\n", quickmod(a, b, len));
return 0;
}
五、二巧板
1.思路
签到题,就是求两个三角形的面积之和。
2.参考代码
#include<bits/stdc++.h>
using namespace std;
const double PI = acos(-1.0);
const double eps = 1e-8;
int sgn(double x)
{
if (fabs(x) < eps)return 0;
else return x < 0 ? -1 : 1;
}
struct Point {
double x, y;
Point() {}
Point(double x, double y) :x(x), y(y) {}
Point operator + (Point B) { return Point(x + B.x, y + B.y); }
Point operator - (Point B) { return Point(x - B.x, y - B.y); }
Point operator * (double k) { return Point(x * k, y * k); }
Point operator / (double k) { return Point(x / k, y / k); }
};
double Cross(Point A, Point B)//叉积
{
return A.x * B.y - A.y * B.x;
}
double Area(Point A, Point B, Point C)//三角形面积*2
{
return Cross(B - A, C - A);
}
int main()
{
Point A, B, C, A1, B1, C1;
scanf("%lf%lf%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y);
scanf("%lf%lf%lf%lf%lf%lf", &A1.x, &A1.y, &B1.x, &B1.y, &C1.x, &C1.y);
double ans = fabs(Area(A, B, C) / 2) + fabs(Area(A1, B1, C1) / 2);
printf("%.2lf\n", ans);
}
六、日常诈骗签到题
1.思路
看到这题,就想起了第一届河北工业大学程序设计竞赛校赛(同步赛)的J题,题面相似,而且那题也是差不多很简单,拿到这题我也没往难的程度想,最后发现答案竟然是
∑ i = 1 n i \displaystyle\sum_{i=1}^{n} i i=1∑ni,然后运用等差数列求和公式轻松A掉。
赛后自己还是手动推了一下,因为数学能力有限还是没能推到这个答案,但是却发现了一种新的思路—欧拉函数+整除分块
∑
i
=
1
n
∑
j
=
1
i
∑
d
=
1
j
n
i
μ
(
d
)
[
d
∣
i
]
[
d
∣
j
]
\displaystyle\sum_{i=1}^{n} \displaystyle\sum_{j=1}^{i}\displaystyle\sum_{d=1}^{j}\frac{n}{i} μ(d)[d∣i][d∣j]
i=1∑nj=1∑id=1∑jinμ(d)[d∣i][d∣j]
=
∑
i
=
1
n
n
i
∑
j
=
1
i
∑
d
=
1
j
μ
(
d
)
[
d
∣
g
c
d
(
i
,
j
)
]
=\displaystyle\sum_{i=1}^{n}\frac{n}{i} \displaystyle\sum_{j=1}^{i}\displaystyle\sum_{d=1}^{j} μ(d)[d|gcd(i,j)]
=i=1∑ninj=1∑id=1∑jμ(d)[d∣gcd(i,j)]
=
∑
i
=
1
n
n
i
∑
j
=
1
i
[
g
c
d
(
i
,
j
)
=
=
1
]
=\displaystyle\sum_{i=1}^{n}\frac{n}{i} \displaystyle\sum_{j=1}^{i}[gcd(i,j)==1]
=i=1∑ninj=1∑i[gcd(i,j)==1]
=
∑
i
=
1
n
n
i
φ
(
i
)
=\displaystyle\sum_{i=1}^{n}\frac{n}{i}φ(i)
=i=1∑ninφ(i)
这不就整除分块+欧拉函数也能AC了嘛!!!!
2.参考代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll M = 1e9 + 7;
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
ll x;
scanf("%lld", &x);
ll xx = (x * x + x) / 2;
xx %= M;
printf("%lld\n", xx);
}
}
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6 + 10;
const ll M = 1e9 + 7;
ll sum[maxn];
ll prime[maxn];
bool vis[maxn];
int cnt;
void Prime()
{
sum[1] = 1;
for (int i = 2; i < maxn; i++)
{
if (vis[i] == false)
{
prime[cnt++] = i;
sum[i] = i - 1;
}
for (int j = 0; prime[j] * i < maxn; j++)
{
vis[prime[j] * i] = true;
if (i % prime[j] == 0)
{
sum[prime[j] * i] = sum[i] * prime[j] % M;
break;
}
else sum[prime[j] * i] = sum[i] * (prime[j] - 1) % M;
}
}
for (int i = 1; i < maxn; i++)
sum[i] = (sum[i - 1] + sum[i]) % M;
}
int main()
{
Prime();
int t;
scanf("%d", &t);
while (t--)
{
ll n;
scanf("%lld", &n);
ll ans = 0;
for (ll l = 1, r; l <= n; l = r + 1)
{
r = min(n, n / (n / l));
ans = (ans + (sum[r] - sum[l - 1]) * (n / l) % M) % M;
}
printf("%lld\n", ans);
}
}
七、jzgg,云哥,沙烬巨巨为什么这么强
1.思路
题面吓死人,其实比较简单,只需要将输入的字符串进行一下简单处理,求出它要消耗的能量值,然后用区间DP模板或者放入优先队列即可解决。 在处理字符串时,难点在于求出它将前导0消除后的最长上升子序列长度,但是也是套模板即可。
2.参考代码
直接套用区间DP板子:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll inf = 0x3f3f3f3f;
const int maxn = 2e3 + 10;
ll a[maxn];
int n;
int dp1[maxn];
ll dp[maxn][maxn];
ll sum[maxn];
ll LAS(string s)
{
memset(dp1, 0, sizeof(dp1));
int x = 0;
while (x < s.length() && s[x] == '0')x++;
vector<ll>v; v.push_back(0);
for (int i = x; i < s.length(); i++)
v.push_back(s[i] - '0');
int ans = s[x];
ans *= (v.size() - 1);
ll len = 0;
for (int i = 1; i < v.size(); i++)
{
if (v[i] > dp1[len] || len == 0)dp1[++len] = v[i];
else
{
int l = 1, r = len;
while (l < r)
{
int mid = (l + r) >> 1;
if (dp1[mid] >= v[i])r = mid;
else l = mid + 1;
}
dp1[l] = v[i];
}
}
ans *= len;
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
memset(dp, inf, sizeof(dp));
for (int i = 1; i <= n; i++)
{
string s;
cin >> s;
a[i] = LAS(s);
sum[i] = sum[i - 1] + a[i];
dp[i][i] = 0;
}
for (int len = 1; len <= n; len++)
{
for (int j = 1; j + len <= n + 1; j++)
{
int ends = j + len - 1;
for (int i = j; i < ends; i++)
{
dp[j][ends] = min(dp[j][ends], dp[j][i] + dp[i + 1][ends] + sum[ends] - sum[j - 1]);
}
}
}
cout << dp[1][n] << endl;
}
用优先队列每次对两个最小值进行操作,然后求出它们对答案的贡献即可:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e3 + 10;
int n;
int dp1[maxn];
ll LAS(string s)
{
memset(dp1, 0, sizeof(dp1));
int x = 0;
while (x < s.length() && s[x] == '0')x++;
vector<ll>v; v.push_back(0);
for (int i = x; i < s.length(); i++)
v.push_back(s[i] - '0');
int ans = s[x];
ans *= (v.size() - 1);
ll len = 0;
for (int i = 1; i < v.size(); i++)
{
if (v[i] > dp1[len] || len == 0)dp1[++len] = v[i];
else
{
int l = 1, r = len;
while (l < r)
{
int mid = (l + r) >> 1;
if (dp1[mid] >= v[i])r = mid;
else l = mid + 1;
}
dp1[l] = v[i];
}
}
ans *= len;
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
priority_queue<ll, vector<ll>, greater<ll>> q;
for (int i = 1; i <= n; i++)
{
string s;
cin >> s;
q.push(LAS(s));
}
ll ans = 0;
while (q.size() >= 2)
{
ll sum=0;
sum += q.top();
q.pop();
sum += q.top();
q.pop();
q.push(sum);
ans+=sum;
}
cout << ans << endl;
}
八、呜米喵想要成为爱抖露!
1.思路
脑瘫最小生成树,签到题,只需要在输入边权值的时候判断权值是否为质数,当为质数时将边权值改为0即可,然后直接套板子则可A掉。
2.参考代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 2e5 + 10;
const int N = 1e7 + 10;
ll s[maxn];
ll prime[N];
bool vis[N];
int cnt;
struct edge {
ll l, r;
ll val;
}a[maxn];
void Prime()
{
for (int i = 2; i < N; i++)
{
if (vis[i] == false) prime[cnt++] = i;
for (int j = 0; i * prime[j] < N; j++)
{
vis[i * prime[j]] = true;
if (i % prime[j] == 0) break;
}
}
}
bool cmp(edge x, edge y)
{
return x.val < y.val;
}
void init()
{
for (int i = 1; i < maxn; i++)
s[i] = i;
}
int find(int x)
{
if (s[x] != x)s[x] = find(s[x]);
return s[x];
}
int main()
{
Prime();
ll n,m,k;
init();
scanf("%lld%lld", &n, &m);
scanf("%lld", &k);
for (int i = 1; i <= m; i++)
{
ll l, r;
ll val;
scanf("%lld%lld%lld", &l, &r, &val);
if (!vis[val])val = 0;
a[i] = { l,r,val };
}
int ans = 0;
int flag = 0;
sort(a + 1, a + 1 + m, cmp);
for (int i = 1; i <= m; i++)
{
int xx, yy;
xx = find(a[i].l);
yy = find(a[i].r);
if (xx != yy)
{
flag++;
s[xx] = s[yy];
ans += a[i].val;
}
if (flag == n - 1)break;
if(ans>=k)break;
}
if (flag == n - 1 && ans < k)printf("wmmxycwdjdwdlnljbzwtskirakira\n");
else printf("wmmxycwdjdwdlnljbzwtsfljt\n");
}
九、MeUmy的海底捞抽奖旅程
传送门
不会,我是fw!
十、MeUmy吃海底捞
传送门
不会,不会,还是不会!
十一、VUP Information Management Favorite
传送门
老模拟题了,但是太复杂了,搞人心态呀。
十二、来签到
1.思路
思路就是水群!!!!!!!!!!
2.参考代码
B
A
AB
ACD
ABD
A
BD
D
BCD
A