传送门
A - Maximum Multiple
推一下式子暴力判断即可,范围不会太大。
Code
#include
typedef long long ll;
typedef double db;
using namespace std;
int a[15][3]{
{2,3,6},
{2,4,4},
{2,6,3},
{3,2,6},
{3,3,3},
{3,6,2},
{4,2,4},
{4,4,2},
{6,2,3},
{6,3,2}
};
int t,n;
int main(){
ios::sync_with_stdio(false);
cin>>t;
while(t--){
cin>>n;
ll ans=-1;
for(int i=0;i<10;i++){
if(n%a[i][0]==0 && n%a[i][1]==0 && n%a[i][2]==0){
ans = max(ans,(ll)(n/a[i][0])*(n/a[i][1])*(n/a[i][2]));
}
}
cout<
B - Balanced Sequence
题意:
给出\(n\)个串,现在定义“好串”:
- 空串;
- 若\(A,B\)为“好串”,那么\(AB\)会“好串”;
- 若\(A\)为“好串”,那么\((A)\)为“好串”。
现在可以对\(n\)个串的顺序任意排列之后拼接起来,问最长“好串”子序列的长度。
思路:
- 对于每个串,先处理出合法括号序列记入答案,那么最后每个串都形如\("))))((("\)的形式,我们将其记为\((L,R)\),表示左括号和右括号分别有多少个。
- 接下来考虑怎么安排顺序使得答案最优。
- 考虑两个的情况,那么答案为\(min(L_1,R_2)\)及\(min(R_1,L_2)\),这时我们按照\(min(L_1,R_2)
的顺序放置即可。 - 为什么?
- 注意一下当\(min(L_1,R_2)=min(R_1,L_2)\)时,我们要按照\(L\)从大到小排序,这可以让更多的\(L\)对后面产生贡献。
详见代码:
Code
#include
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
//#define Local
using namespace std;
typedef long long ll;
typedef pair pii;
const int N = 1e5 + 5;
int n;
char s[N];
int sta[N], top;
struct Point{
int L, R;
bool operator < (const Point &A)const {
int p = min(R, A.L), q = min(L, A.R);
if(p == q) return L > A.L;
return p < q;
}
}p[N];
void run() {
cin >> n;
int ans = 0;
for(int i = 1; i <= n; i++) {
cin >> s + 1;
int len = strlen(s + 1);
int l = 0, r = 0;
top = 0;
for(int j = 1; j <= len; j++) {
if(top && s[sta[top]] == '(' && s[j] == ')') --top, ++ans;
else sta[++top] = j;
}
for(int j = 1; j <= top; j++) {
if(s[sta[j]] == '(') ++l;
else ++r;
}
p[i] = {l, r};
}
sort(p + 1, p + n + 1);
int l = 0, r = 0;
for(int i = 1; i <= n; i++) {
int now = min(l, p[i].R);
ans += now;
l = l - now + p[i].L;
}
cout << ans * 2 << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
int T; cin >> T;
while(T--) run();
return 0;
}
C - Triangle Partition
排序每次选左边的就行。
Code
#include
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
//#define Local
using namespace std;
typedef long long ll;
typedef pair pii;
const int N = 3e3 + 5;
struct Point{
int x, y, id;
bool operator < (const Point &A) const {
return x < A.x;
}
}p[N];
int n;
void run() {
cin >> n;
for(int i = 1; i <= 3 * n; i++) {
cin >> p[i].x >> p[i].y;
p[i].id = i;
}
sort(p + 1, p + 3 * n + 1);
for(int i = 1; i <= 3 * n; i += 3) {
cout << p[i].id << ' ' << p[i + 1].id << ' ' << p[i + 2].id << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
int T; cin >> T;
while(T--) run();
return 0;
}
D - Distinct Values
题意:
构造字典序最小的序列,满足在给出的区间中数字各不重复。
思路:
- 对于每个位置,能影响它的区间显然从左端点最远起。
- 发现随着位置的不断增加,最远位置具有单调性。
- 那么利用\(set\)随便搞搞就行了,\(set\)里面的就插入可以用的数,每次取最小的就行。
比赛的时候写了个权值线段树求区间\(mex\)的做法,维护所有权值最后出现的最小值就行,然后贪心选权值。还是搞复杂了= =思维还是不够灵活。
Code
#include
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
const int MAXN = 1e5+5,MAXM = 1e6+5,MOD = 100003,INF = 0x3f3f3f3f;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const db eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define pii pair
#define vii vector
#define vi vector
using namespace std;
struct line{
int l,r;
bool operator <(const line &rhs)const{
return l==rhs.l?r>rhs.r:l>t;
while(t--){
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>a[i].l>>a[i].r;
sort(a+1,a+1+m);
build(1,1,n);
int pre=0;
for(int i=1;i<=n;i++)ans[i]=1;
for(int i=1;i<=m;i++){
if(a[i].r <= pre)continue;
for(int j=pre+1;j<=a[i].r;j++){
ans[j] = ask(1,1,n,a[i].l);
upd(1,1,n,ans[j],j);
}
pre=a[i].r;
}
for(int i=1;i<=n;i++)cout<
G - Chiaki Sequence Revisited
题意:
定义:
\[ a_n=\left\{ \begin{aligned} &1&n=1,2\\ &a_{n-a_{n-1}}+a_{n-1-{a_{n-2}}}&n > 2 \end{aligned} \right. \]
先求\(\sum_{i=1}^n{a_i}\),\(n\leq 10^{18}\)。
思路:
懒得写啦,有博客写得很好:传送门。
找规律的时候想到二进制基本规律就出来了,核心就是找到出现次数的规律就行。
代码有些细节,因为根据规律,\(1\)只会出现一次,但实际上会出现两次,所以我们将\(n\)偏移一下即可。另外注意我们找\(x\)的时候,要找\(f(x)\leq a_n\)的最大\(x\),这里有个等于是为了方便处理数据较小时的情况。
详见代码:
Code
#include
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
using namespace std;
typedef long long ll;
typedef pair pii;
const int N = 1e5 + 5, MOD = 1e9 + 7, inv2 = (MOD + 1) / 2;
ll n;
ll calc(ll k) {
if(k <= 1) return k;
return calc(k / 2) + k;
}
void run() {
cin >> n; --n;
ll l = n / 2 - 50, r = n / 2 + 50, mid;
while(l < r) {
mid = (l + r) >> 1;
if(calc(mid) > n) r = mid;
else l = mid + 1;
}
ll p = r - 1;
ll res = (n - calc(p)) % MOD;
ll ans = 0;
for(ll d = 1, c = 1; ; d <<= 1, ++c) {
if(d > p) break;
ll s = d % MOD;
ll k = ((p - d) / (2 * d) + 1) % MOD;
ll e = (s + (k - 1) * 2ll % MOD * d % MOD) % MOD;
ans = (ans + c * (s + e) % MOD * k % MOD * inv2 % MOD) % MOD;
}
ans += (res * ((p + 1) % MOD) % MOD + 1) % MOD;
ans %= MOD;
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
int T; cin >> T;
while(T--) run();
return 0;
}
H - RMQ Similar Sequence
题意:
定义\(RMQ(A, l, r)\)表示\(A\)数组中\([l,r]\)区间最大值的位置。
现在给出序列\(A\),然后随机生成一个序列\(B\),\(B\)中的每个值都在\(0\)到\(1\)之间。问满足对于\(1\leq l\leq r\leq n\),都有\(RMQ(A, l, r)=RMQ(B,l ,r)\)的\(B\)序列的期望权值和为多少。
思路:
- 显然题目中给出的\(RMQ(A, l, r)=RMQ(B, l, r)\)则为两颗笛卡尔树同构,那么求出\(A\)的笛卡尔树,\(B\)的笛卡尔树形态也确定了。
- \(B\)随机生成的一个实数的期望值为\(\frac{1}{2}\),那么期望和为\(\frac{n}{2}\),接下来主要任务就是求树同构的概率。
- 我们可以认为\(B\)序列中的两两数各不相同,因为出现重复的数可以认为概率为\(0\),那么这就相当于一个排列,现在要将这个排列挂在一颗树上并且满足大根堆的性质。
- 总的方案数为\(n!\),但是对于一颗子树而言,其最大值为根的情况只有\(\frac{1}{sz_i}*n!\);因为以每个结点为根的方案数是独立的,那么满足条件的总的方案数则为\(\frac{n!}{\prod sz_i}\)。概率就很好求了~
代码如下:
Code
#include
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
//#define Local
using namespace std;
typedef long long ll;
typedef pair pii;
const int N = 1e6 + 5, MOD = 1e9 + 7;
int n;
int a[N];
pii b[N];
ll qpow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
struct Cartesian_Tree{
struct node{
int id, val, fa;
int son[2];
node(){}
node(int id, int val, int fa) : id(id), val(val), fa(fa) {
son[0] = son[1] = 0;
}
}tr[N];
int rt;
void init() {
tr[0] = node(0, 1e9, 0);
}
void build(int n, int *a) {
for(int i = 1; i <= n; i++) tr[i] = node(i, a[i], 0);
for(int i = 1; i <= n; i++) {
int k = i - 1;
while(tr[k].val < tr[i].val) k = tr[k].fa;
tr[i].son[0] = tr[k].son[1];
tr[k].son[1] = i;
tr[i].fa = k;
tr[tr[i].son[0]].fa = i;
}
rt = tr[0].son[1];
}
int dfs(int u) {
if(!u) return 0;
int lsz = dfs(tr[u].son[0]);
int rsz = dfs(tr[u].son[1]);
b[tr[u].id].fi = lsz;
b[tr[u].id].se = rsz;
return lsz + rsz + 1;
}
}CT;
void run() {
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
CT.init();
CT.build(n, a);
CT.dfs(CT.rt);
ll res = 2;
for(int i = 1; i <= n; i++) {
res = res * (b[i].fi + b[i].se + 1) % MOD;
}
res = qpow(res, MOD - 2) * n % MOD;
cout << res << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cout << fixed << setprecision(20);
#ifdef Local
freopen("../input.in", "r", stdin);
freopen("../output.out", "w", stdout);
#endif
int t; cin >> t;
while(t--) run();
return 0;
}
K - Time Zone
模拟。
Code
#include
using namespace std;
template
struct A{
T data[z];
int n;
A():n(0) {}
T& operator[](int q) {return data[q];}
inline void push(T x) {data[n++]=x;}
inline T& pop() {return data[--n];}
};
char x[10];
int main() {
int T; scanf("%d", &T);
while(0=60) {
a++,b-=60;
}
while(b<0) {
b+=60,a--;
}
while(a>=24) a-=24;
while(a<0) a+=24;
printf("%02d:%02d\n", a,b);
}
return 0;
}