比赛链接
A
枚举
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <set>
using namespace std;
const int inf = 0x3f3f3f3f;
const int b[] = {'A' - 'A', 'C' - 'A', 'T' - 'A', 'G' - 'A'};
char str[55];
int n, a[55], ans = inf;
inline int len (int x, int y){
return min(abs(x - y), 26 - abs(x - y));
}
int main(){
scanf("%d%s", &n, str + 1);
for(int i = 1; i <= n; ++i) a[i] = str[i] - 'A';
for(int i = 1; i <= n - 3; ++i){
int res = 0;
for(int j = i; j < i + 4; ++j)
res += len(a[j], b[j - i]);
ans = min(ans, res);
}
printf("%d", ans);
return 0;
}
B
n*m矩阵 从每一行选一个数 使得异或和不为零 (n,m leq 500)
每行都取第一个 如果异或和为零的话 看能不能在某一行换一个不同的数
如果有的话 那异或和一定不为零
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <bitset>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, m, pos, val;
bool rec[2000];
int a[505][505];
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j]);
int fir, pos = 0, val, sum = 0;
for(int i = 1; i <= n; ++i){
fir = a[i][1], sum ^= fir;
for(int j = 2; j <= m; ++j)
if(a[i][j] != fir)
pos = i, val = j;
}
if(sum | pos){
puts("TAK");
for(int i = 1; i <= n; ++i)
if(!sum && pos == i) printf("%d ", val);
else printf("1 ");
}
else puts("NIE");
return 0;
}
C
求[l, r]区间和 对1e9 + 7取模
(1 / 2 4 / 3 5 7 9 / 6 8 10 12 / ... / 2^n 个连续奇数 / 2^(n + 1)个连续偶数)
(l, r leq 1e18)
统计[1, n]的话就算出前n个里有多少个奇数 多少个偶数
等差数列求和加一下再做个前缀和的差
include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <bitset>
#define node(x, y) ((x << 1) - y)
using namespace std;
typedef long long ll;
const int N = 105;
const ll P = 1e9 + 7;
ll L, R;
inline ll solve(ll n){
ll a[2] = {}, i = 1, j = 0;
while(n - a[0] - a[1] > 0)
a[j] += min(n - a[0] - a[1], i),
i <<= 1, j ^= 1;
a[0] %= P, a[1] %= P;
return (a[0] * a[0] + a[1] * a[1] + a[1]) % P;
}
int main(){
scanf("%lld%lld", &L, &R);
printf("%lld
", (solve(R) + P - solve(L - 1)) % P);
return 0;
}
D
长度为n的序列 每个点有两个值a[i], b[i]
(ans = sum_{i = 1}^{i <= n} a[i] * (i - 1) + b[i] * (n - i))
求(ans_{min}) (n leq 1e5)
这道题很国王游戏啊
如果要交换相邻两个数i, i + 1的话
ans = ans + a[i] - a[i + 1] - b[i] + b[i + 1]
所以按照a[i] - b[i]排序就好啦
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <bitset>
using namespace std;
typedef long long ll;
const ll P = 1e9 + 7;
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;
int n, id[N];
ll ans, a[N], b[N];
inline bool rule(int x, int y){
return a[x] - b[x] > a[y] - b[y];//不要在比较函数里用小于等于
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%lld%lld", &a[i], &b[i]), id[i] = i;
sort(id + 1, id + n + 1, rule);
for(int i = 1; i <= n; ++i) ans += 1ll * a[id[i]] * (i - 1) + 1ll * b[id[i]] * (n - i);
printf("%lld
", ans);
return 0;
}
E
有一个长度为n的链 每个点权值为a[]
f(l, r)表示仅保留满足(l leq a[] leq r)的点时,有多少个连通块
统计所有取值区间的f之和 取模1e9 + 7
(n, a[] leq 1e5)
考虑每个数作为区间右端点的贡献
然后排掉左边点对它的限制
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <bitset>
#define node(x, y) ((x << 1) - y)
using namespace std;
typedef long long ll;
int n;
ll ans;
int main(){
int pre, x;
scanf("%d%d", &n, &pre);
ans += 1ll * pre * (n - pre + 1);
for(int i = 2; i <= n; ++i){
scanf("%d", &x);
if(pre > x) ans += 1ll * x * (pre - x);
else ans += 1ll * (n - x + 1) * (x - pre);
pre = x;
}
printf("%lld", ans);
return 0;
}
F
给定长度为n的01序列 做m次操作
每次操作等概率选取两位置 交换两位置的值
求m次操作结束后 序列中所有0在所有1前面的概率
(n leq 100, m leq 1e9)
假设一共有cnt个0
f[i] 表示前cnt个数里有i个是0的概率
矩阵快速幂转移即可
竟然被一个数竞党虐了qvq菜死了
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
#include <vector>
#include <map>
#define P(x, y) 1ll * (x) * inv(y) % P
using namespace std;
typedef long long ll;
const int N = 105;
const ll P = 1e9 + 7;
/*orz wjs*/
inline ll add(ll x, ll y){
x += y; return x >= P ? x - P : x;
}
inline ll sub(ll x, ll y){
x -= y; return x < 0 ? x + P : x;
}
map<ll, ll> INV;
inline ll inv(ll x){
if(!INV[x]){
int y = P - 2; ll res = 1;
while(y){
if(y & 1) res = res * x % P;
x = x * x % P; y >>= 1;
}
INV[x] = res;
//printf("inv %lld %lld
", x, INV[x]);
}
return INV[x];
}
struct Matrix{
ll w[N][N];
int lim;
void clear(int x){
lim = x; memset(w, 0, sizeof(w));
}
void init(int x){
clear(x); for(int i = 0; i <= lim; ++i) w[i][i] = 1;
}
friend Matrix operator * (Matrix x, Matrix y){
Matrix z; z.clear(x.lim);
for(int i = 0; i <= z.lim; ++i)
for(int j = 0; j <= z.lim; ++j)
for(int k = 0; k <= z.lim; ++k)
z.w[i][j] = add(z.w[i][j], x.w[i][k] * y.w[k][j] % P);
return z;
}
void print(){
for(int i = 0; i <= lim; ++i){
for(int j = 0; j <= lim; ++j)
printf("%d ", w[i][j]);
printf("
");
}
}
}beg, chg;
int n, m, a[N], cnt;
inline Matrix mpow(Matrix x, int y){
Matrix res; res.init(cnt);
while(y){
if(y & 1) res = res * x;
x = x * x; y >>= 1;
}
return res;
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]), cnt += (a[i] ^ 1);
beg.clear(cnt); chg.clear(cnt);
int tt = 0;
for(int i = 1; i <= cnt; ++i) tt += (a[i] ^ 1);
beg.w[tt][0] = 1;
for(int i = 0; i <= cnt; ++i) if(n + i >= (cnt << 1)){
ll c00 = i, c01 = cnt - i, c10 = cnt - i, c11 = 1ll * n - c00 - c01 - c10;
if(i < cnt) chg.w[i + 1][i] = P(1ll * c01 * c10 % P, 1ll * n * (n - 1) % P * inv(2) % P);
if(i) chg.w[i - 1][i] = P(1ll * c00 * c11 % P, 1ll * n * (n - 1) % P * inv(2) % P);
chg.w[i][i] = sub(1, add(chg.w[i + 1][i], chg.w[i - 1][i]));
}
Matrix res = mpow(chg, m);
res = res * beg;
printf("%lld
", res.w[cnt][0]);
return 0;
}