A:honoka和格点三角形
思路:由于三角形面积为2,而且保证三角形的一边与x轴或y轴平行,从而可以推出与某轴平行的边长度要么是1要么是2.
1.考虑满足题意的三角形中与x轴平行:
- 与x轴平行的边长为2,对答案的贡献:m * (m - 2) % mod * (n - 1) % mod * 2 % mod;
- 与x轴平行的边长为1,对答案的贡献:m * (m - 1) % mod * (n - 2) % mod * 2 % mod;
2.考虑满足题意的三角形中与y轴平行:
- 与y轴平行的边长为2,对答案的贡献(舍弃与x轴平行的三角形,不重复计数):
(n - 2) * (n - 2) % mod * (m - 1) % mod * 2 % mod; - 与y轴平行的边长为1,对答案的贡献(舍弃与x轴平行的三角形,不重复计数):
(n - 2) * (n - 1) % mod * (m - 2) % mod * 2 % mod;
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
ll m, n;
ll solve1(ll n, ll m){
ll ans;
ans = m * (m - 2) % mod * (n - 1) % mod * 2 % mod;
return ans;
}
ll solve2(ll n, ll m){
ll ans;
ans = m * (m - 1) % mod * (n - 2) % mod * 2 % mod;
return ans;
}
ll solve3(ll n, ll m){
ll ans;
ans = (n - 2) * (n - 2) % mod * (m - 1) % mod * 2 % mod;
return ans;
}
ll solve4(ll n, ll m){
ll ans;
ans = (n - 2) * (n - 1) % mod * (m - 2) % mod * 2 % mod;
return ans;
}
int main(){
while(scanf("%lld%lld", &n, &m) != EOF){
ll ans = 0;
ans = solve1(n, m);
ans = (ans + solve2(n, m)) % mod;
ans = (ans + solve3(n, m)) % mod;
ans = (ans + solve4(n, m)) % mod;
printf("%lld\n", ans);
}
return 0;
}
B:kotori和bangdream
思路:由于每一个音符都是等价的,直接利用数学公式求出一个音符的期望值
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll n, a, b, x;
int main(){
while(scanf("%lld%lld%lld%lld", &n, &x, &a, &b) != EOF){
ll up = a * x + b * (100 - x);
up *= n;
double ans = up / 100.0;
printf("%.2f\n", ans);
}
return 0;
}
C:umi和弓道
思路:这道题把题目简化,每一个点都不在坐标轴上。所以我们就可以直接暴力弄,对于与umi在同一象限的,我们就直接忽略(因为你只能把板放在坐标轴上,所以肯定会把在同一象限的打掉)。不在同一象限的点,我们求出umi与它组成的线段与x轴或y轴的交点。与x轴的交点放在桶A,与y轴的交点放在桶B。然后按大小排序后,直接找枚举区间长度为n - k的答案,然后最后取min。具体细节,可以参考代码。
但是我这个代码,处理两个点表示的线段与x或y轴有无交点地方,写得很啰嗦。
处理交点,可以利用此方法 umi(x0, y0) A(x1, y1) if(x0 * x1 < 0) x轴有交点 if(y0 * y1 < 0) y轴有交点
下面大篇幅代码,可以用上面思路简化。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
ll x, y;
int n, k;
vector<double>Y;
vector<double>X;
double Get_Y(ll x0, ll y0, ll x1, ll y1){
if(x0 == x1) return y0 * 1.0;
return (y1 * x0 - x1 * y0) / (1.0 * (x0 - x1));
}
double Get_X(ll x0, ll y0, ll x1, ll y1){
//printf("x1 = %lld y1 = %lld\n", x1, y1);
if(y0 == y1) return x0;
return (x1 * y0 - x0 * y1) / (1.0 * (y0 - y1));
}
int check(ll x, ll y){
if(x > 0 && y > 0) return 1;
if(x > 0 && y < 0) return 4;
if(x < 0 && y > 0) return 2;
if(x < 0 && y < 0) return 3;
}
void print(){
int Size = X.size();
for(int i = 0; i < Size; i++){
printf("X[%d] = %f\n", i + 1, X[i]);
}
Size = Y.size();
for(int i = 0; i < Size; i++){
printf("Y[%d] = %f\n", i + 1, Y[i]);
}
}
int main(){
while(scanf("%lld%lld%d%d", &x, &y, &n, &k) != EOF){
Y.clear(); X.clear();
int res = n - k;
ll f, s;
int opt = check(x, y);
for(int i = 1; i <= n; i++){
scanf("%lld%lld", &f, &s);
int tmp = check(f, s);
if(opt == tmp) continue;
if(opt == 1){
if(tmp == 2){
double y1 = Get_Y(x, y, f, s);
Y.push_back(y1);
}
else if(tmp == 3){
double y1 = Get_Y(x, y, f, s);
Y.push_back(y1);
double x1 = Get_X(x, y, f, s);
X.push_back(x1);
}
else{
double x1 = Get_X(x, y, f, s);
X.push_back(x1);
}
}
if(opt == 2){
if(tmp == 1){
double y1 = Get_Y(x, y, f, s);
Y.push_back(y1);
}
else if(tmp == 3){
double x1 = Get_X(x, y, f, s);
X.push_back(x1);
}
else{
double y1 = Get_Y(x, y, f, s);
Y.push_back(y1);
double x1 = Get_X(x, y, f, s);
X.push_back(x1);
}
}
if(opt == 3){
if(tmp == 1){
double y1 = Get_Y(x, y, f, s);
Y.push_back(y1);
double x1 = Get_X(x, y, f, s);
X.push_back(x1);
}
else if(tmp == 2){
double x1 = Get_X(x, y, f, s);
X.push_back(x1);
}
else{
double y1 = Get_Y(x, y, f, s);
Y.push_back(y1);
}
}
if(opt == 4){
if(tmp == 1){
double x1 = Get_X(x, y, f, s);
X.push_back(x1);
}
else if(tmp == 2){
double y1 = Get_Y(x, y, f, s);
Y.push_back(y1);
double x1 = Get_X(x, y, f, s);
X.push_back(x1);
}
else{
double y1 = Get_Y(x, y, f, s);
Y.push_back(y1);
}
}
}
sort(X.begin(), X.end());
sort(Y.begin(), Y.end());
int Size = X.size();
double ans = 1e15;
for(int i = 0; i + res - 1 < Size; i++){
int j = i + res - 1;
ans = min(ans, X[j] - X[i]);
}
Size = Y.size();
for(int i = 0; i + res - 1 < Size; i++){
int j = i + res - 1;
ans = min(ans, Y[j] - Y[i]);
}
//print();
if(ans == 1e15) printf("-1\n");
else printf("%.8f\n", ans);
}
return 0;
}
D:hanayo和米饭
思路:直接暴力枚举1-n谁没出现即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int n;
bool vis[maxn];
int main(){
while(scanf("%d", &n) != EOF){
int val;
for(int i = 1; i < n; i++) scanf("%d", &val), vis[val] = true;
for(int i = 1; i <= n; i++){
if(!vis[i]) printf("%d\n", i);
}
}
return 0;
}
E:rin和快速迭代
思路:f(x)表示x的因数个数 设x的质因数为,质因数对应的指数为
,那么
感想:当时做这题的时候,我求质因数指数,算了一下大概复杂度是。可是,我在暴力跑1e12的时候,发现迭代次数好像挺小的,于是就暴力莽了一发,居然过了。但是数学证明我不太会,如果有会的,希望有人可以留言告诉我!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll n;
ll Get(ll n){
ll ans = 1;
for(ll i = 2; i * i <= n; i++){
if(n % i == 0){
int num = 1;
while(n % i == 0){
num++;
n /= i;
}
ans *= num;
}
}
if(n > 1) ans *= 2;
return ans;
}
int main(){
while(scanf("%lld", &n) != EOF){
ll num = 0;
while(n != 2){
num++;
n = Get(n);
}
printf("%lld\n", num);
}
return 0;
}
F:maki和tree
思路:理解统计方法后,我们发现黑点是特殊点,可以枚举。怎么枚举呢?
枚举其中一个黑点A,怎么统计这个点对答案的贡献呢?
我们把这棵树除黑点A的其余黑点从树中拿掉,这下就变成很多棵树。黑点A所在的那棵树就发现贡献计算公式,这个就显然求出贡献值。如果不懂,可以看代码。
所以可以用并查集维护白点集合的大小,方便统计答案
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll siz[maxn];
int fa[maxn];
int n;
char s[maxn];
vector<int>pos[maxn];
int find_fa(int x){
if(x != fa[x]) return fa[x] = find_fa(fa[x]);
return x;
}
void join(int x, int y){
x = find_fa(x);
y = find_fa(y);
if(x == y) return ;
fa[x] = y;
siz[y] += siz[x];
}
int main(){
while(scanf("%d", &n) != EOF){
scanf("%s", s + 1);
int x, y;
for(int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1, pos[i].clear();
for(int i = 1; i < n; i++){
scanf("%d%d", &x, &y);
if(s[x] == 'W' && s[y] == 'W'){
join(x, y);
}
if(s[x] == 'W' && s[y] == 'B'){
pos[y].push_back(x);
}
if(s[x] == 'B' && s[y] == 'W'){
pos[x].push_back(y);
}
}
ll ans = 0;
for(int i = 1; i <= n; i++){
if(s[i] == 'B'){
ll sum = 0, sum_1 = 0;
int Size = pos[i].size();
for(int j = 0; j < Size; j++){
sum += siz[find_fa(pos[i][j])];
}
ans += sum;
for(int j = 0; j < Size; j++){
ll num = siz[find_fa(pos[i][j])];
sum_1 += num * (sum - num);
}
ans += sum_1 / 2;
}
}
printf("%lld\n", ans);
}
return 0;
}
G:eli和字符串
思路:开26个桶记录位置,然后固定长度更新答案
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int n, k;
vector<int>pos[30];
char s[maxn];
int main(){
while(scanf("%d%d", &n, &k) != EOF){
scanf("%s", s + 1);
for(int i = 1; i <= n; i++){
int in = s[i] - 'a' + 1;
pos[in].push_back(i);
}
int ans = maxn;
for(int i = 1; i <= 26; i++){
int Size = pos[i].size();
if(Size < k) continue;
for(int j = 0; j + k - 1 < Size; j++){
int r = j + k - 1;
ans = min(ans, pos[i][r] - pos[i][j] + 1);
}
}
if(ans == maxn) printf("-1\n");
else printf("%d\n", ans);
}
return 0;
}
H:nozomi和字符串
思路:求最大值,发现具有二分性,所以利用左闭右开区间。
check函数如何写呢?
对于二分的一个答案len,以此固定长度枚举区间,判断是否把01区间转化为全0或全1,利用前缀和即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int pre[maxn];
char s[maxn];
int n, k;
bool check(int len){
for(int i = 1; i + len - 1 <= n; i++){
int j = i + len - 1;
int sum = pre[j] - pre[i - 1];
if(min(len - sum, sum) <= k) return true;
}
return false;
}
void print(){
for(int i = 1; i <= n; i++){
printf("pre[%d] = %d\n", i, pre[i]);
}
}
int main(){
while(scanf("%d%d", &n, &k) != EOF){
scanf("%s", s + 1);
for(int i = 1; i <= n; i++){
int val = s[i] - '0';
pre[i] = pre[i - 1] + val;
}
//print();
int l, r;
l = 1, r = n + 1;
while(r - l > 1){
int mid = (l + r) / 2;
if(check(mid)){
l = mid;
}
else{
r = mid;
}
}
printf("%d\n", l);
}
return 0;
}
I:nico和niconiconi
思路:简单dp,dp[i]表示从开头到第i个字符获得的最大分数
更新3种方式
dp[i] = max(dp[i], dp[i - 4] + a);
dp[i] = max(dp[i], dp[i - 6] + b);
dp[i] = max(dp[i], dp[i - 10] + c);
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 5;
ll dp[maxn];
string s1 = "nico", s2 = "niconi", s3 = "niconiconi";
ll a, b, c, n;
char s[maxn];
bool check(int l, int r, int opt){
if(l <= 0) return false;
if(opt == 1){
int Size = s1.size();
for(int i = 0; i < Size; i++){
if(s[i + l] != s1[i]) return false;
}
}
if(opt == 2){
int Size = s2.size();
for(int i = 0; i < Size; i++){
if(s[i + l] != s2[i]) return false;
}
}
if(opt == 3){
int Size = s3.size();
for(int i = 0; i < Size; i++){
if(s[i + l] != s3[i]) return false;
}
}
return true;
}
int main(){
while(scanf("%lld%lld%lld%lld", &n, &a, &b, &c) != EOF){
scanf("%s", s + 1);
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++){
dp[i] = dp[i - 1];
if(check(i - 3, i, 1)){
dp[i] = max(dp[i], dp[i - 4] + a);
}
if(check(i - 5, i, 2)){
dp[i] = max(dp[i], dp[i - 6] + b);
}
if(check(i - 9, i, 3)){
dp[i] = max(dp[i], dp[i - 10] + c);
}
}
printf("%lld\n", dp[n]);
}
return 0;
}
J:u's的影响力
思路:乘法可以联想指数加法,然后写几个例子,发现指数呈现斐波拉契变化。
注意几个坑点:由于x,y,a很大,所以我们要先取模,防止利用快速幂时爆long long
利用欧拉降幂条件 1
,所以坑点就是要判断a与p是否互质
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct mat{
int r, c;
ll a[5][5];
mat(){
memset(a, 0, sizeof(a));
}
};
mat mul(mat A, mat B, ll mod){
mat C;
C.r = A.r; C.c = B.c;
for(int i = 1; i <= C.r; i++){
for(int j = 1; j <= C.c; j++){
for(int k = 1; k <= A.c; k++){
C.a[i][j] += A.a[i][k] * B.a[k][j] % mod;
C.a[i][j] %= mod;
}
}
}
return C;
}
mat power(mat A, ll b, ll mod){
mat res;
res.c = res.r = A.r;
for(int i = 1; i <= res.r; i++) res.a[i][i] = 1;
while(b){
if(b & 1) res = mul(res, A, mod);
b >>= 1;
A = mul(A, A, mod);
}
return res;
}
ll quick_mod(ll a, ll b, ll mod){
ll sum = 1;
while(b){
if(b & 1) sum = sum * a % mod;
a = a * a % mod;
b /= 2;
}
return sum;
}
int main(){
ll m = 1e9 + 7, ans = 1;
ll n, x, y, a, b;
cin >> n >> x >> y >> a >> b;
if(n == 1) {cout << x % m << endl; return 0;}
if(n == 2) {cout << y % m << endl; return 0;}
if(x % m == 0 || y % m == 0 || a % m == 0) {cout << 0 << endl; return 0;}
x %= m;
y %= m;
a = quick_mod(a % m, b, m); ///这里要注意a对m取模
mat a_; a_.r = a_.c = 2; a_.a[1][1] = a_.a[1][2] = a_.a[2][1] = 1;
mat opt1, opt2;
opt1.r = opt2.r = 2; opt1.c = opt2.c = 1;
opt1.a[1][1] = 0; opt1.a[2][1] = 1;
opt2.a[1][1] = 1; opt2.a[2][1] = 0;
a_ = power(a_, n - 2, m - 1);
mat c = mul(a_, opt1, m - 1);
//printf("x = %lld\n", c.a[1][1]);
ans = ans * quick_mod(x, c.a[1][1], m) % m;
c = mul(a_, opt2, m - 1);
//printf("y = %lld\n", c.a[1][1]);
ans = ans * quick_mod(y, c.a[1][1], m) % m;
///
mat d; d.r = d.c = 3; d.a[1][1] = d.a[1][2] = d.a[1][3] = d.a[2][1] = d.a[3][3] = 1;
mat opt3; opt3.r = 3; opt3.c = 1; opt3.a[1][1] = opt3.a[2][1] = 0; opt3.a[3][1] = 1;
d = power(d, n - 2, m - 1);
c = mul(d, opt3, m - 1);
//printf("a = %lld\n", c.a[1][1]);
ans = ans * quick_mod(a, c.a[1][1], m) % m;
printf("%lld\n", ans);
return 0;
}



京公网安备 11010502036488号