[2.7]【CF933A】A Twisty Movement【CF926B】Add Points【CF917A】The Monster【CF919E】Congruence Equation


在这里插入图片描述

T1:A Twisty Movement

题目

题目

题解

因为 a i a_i ai= 1 / 2 1/2 1/2,于是我们可以确定答案一定是: [ 1 , 1 , 1 , … ] [ 2 , 2 , 2 … ] [ 1 , 1 , 1 … ] [ 2 , 2 , 2 … ] [1,1,1,…][2,2,2…][1,1,1…][2,2,2…] [1,1,1,][2,2,2][1,1,1][2,2,2]这样的四段子序列(每一段都允许为空)中第二、三段所在区间翻转得到

我们可以从左往右做前缀和 p r e [ i ] pre[i] pre[i]表示 [ 1 , i ] [1,i] [1,i]出现 1 1 1的个数,后缀和 s u f [ i ] suf[i] suf[i]表示 [ i , n ] [i,n] [i,n]出现 2 2 2的个数


然后我们枚举二、三段的分界点 k , k ∈ [ 1 , n + 1 ] k,k∈[1,n+1] k,k[1,n+1],再设一、二段的分界点为 p , p ∈ [ 1 , k ] p,p∈[1,k] p,p[1,k],三、四段的分界点为 q , q ∈ [ k , n + 1 ] q,q∈[k,n+1] q,q[k,n+1]

那么答案为 ( p r e [ p − 1 ] ) + ( s u f [ p ] − s u f [ k ] ) + ( p r e [ q − 1 ] − p r e [ k ] ) + ( s u f [ q ] ) (pre[p-1])+(suf[p]-suf[k])+(pre[q-1]-pre[k])+(suf[q]) (pre[p1])+(suf[p]suf[k])+(pre[q1]pre[k])+(suf[q])
在这里插入图片描述
将式子中括号括起来的当为一个整体
这个式子可以化为:
( p r e [ p − 1 ] + s u f [ p ] + p r e [ q − 1 ] + s u f [ q ] ) − ( s u f [ k ] + p r e [ k ] ) (pre[p-1]+suf[p]+pre[q-1]+suf[q])-(suf[k]+pre[k]) (pre[p1]+suf[p]+pre[q1]+suf[q])(suf[k]+pre[k])
p ∈ [ 1 , k ] , q ∈ [ k , n + 1 ] p∈[1,k],q∈[k,n+1] p[1,k],q[k,n+1]

发现对于一个确定的 k k k,我们要最大化前面括号的式子
而第一个括号里面的东西可以用线段树维护下 p r e [ i − 1 ] + s u f [ i ] pre[i-1]+suf[i] pre[i1]+suf[i]
那么只用枚举 k k k,再两次区间最大值查询,更新答案就好了

code

#include <cstdio>
#include <iostream>
using namespace std;
#define MAXN 2005
int n, result;
int a[MAXN], pre[MAXN], suf[MAXN], tree[MAXN << 2];

void insert ( int t, int l, int r, int id, int val ) {
	if ( l == r ) {
		tree[t] = val;
		return;
	}
	int mid = ( l + r ) >> 1;
	if ( id <= mid )
		insert ( t << 1, l, mid, id, val );
	else
		insert ( t << 1 | 1, mid + 1, r, id, val );
	tree[t] = max ( tree[t << 1], tree[t << 1 | 1] );
}

int query ( int t, int l, int r, int L, int R ) {
	if ( L <= l && r <= R )
		return tree[t];
	int mid = ( l + r ) >> 1;
	int ans = 0;
	if ( L <= mid )
		ans = max ( ans, query ( t << 1, l, mid, L, R ) );
	if ( mid < R )
		ans = max ( ans, query ( t << 1 | 1, mid + 1, r, L, R ) );
	return ans;
}

int main() {
	scanf ( "%d", &n );
	for ( int i = 1;i <= n;i ++ )
		scanf ( "%d", &a[i] );
	for ( int i = 1;i <= n;i ++ )
		pre[i] = pre[i - 1] + ( a[i] == 1 );
	for ( int i = n;i >= 1;i -- )
		suf[i] = suf[i + 1] + ( a[i] == 2 );
	for ( int i = 1;i <= n + 1;i ++ )
		insert ( 1, 1, n + 1, i, pre[i - 1] + suf[i] );
	for ( int i = 1;i <= n + 1;i ++ ) {
		int tmp1 = query ( 1, 1, n + 1, 1, i ), tmp2 = query ( 1, 1, n + 1, i, n + 1 );
		result = max ( result, tmp1 + tmp2 - pre[i - 1] - suf[i] ); 
	}
	printf ( "%d", result );
	return 0;
}

T2:Add Points

题目

题目

题解

这道题实在不知道怎么讲,我觉得直接扔一句话就懂了
排完序后两两距离的最大公约数

code

#include <cstdio>
#include <algorithm>
using namespace std;
#define MAXN 100005
int n;
int x[MAXN];

int gcd ( int x, int y ) {
	if ( ! y )
		return x;
	else
		return gcd ( y, x % y );
}

int main() {
	scanf ( "%d", &n );
	for ( int i = 1;i <= n;i ++ )
		scanf ( "%d", &x[i] );
	sort ( x + 1, x + n + 1 );
	int d = x[2] - x[1];
	for ( int i = 2;i < n;i ++ ) {
		int dis = x[i + 1] - x[i];
		d = gcd ( d, dis );
	}
	int result = 0;
	for ( int i = 1;i < n;i ++ )
		result += ( x[i + 1] - x[i] ) / d - 1;
	printf ( "%d", result );
	return 0;
}

T3:The Monster

题目

题目

题解

其实还是有点意思,我认为比 T 2 T2 T2要难一点
首先直接纯暴力 2 5000 2^{5000} 25000可以直接当场去世了


考虑枚举起点,用 t o t tot tot记录, ( ( ( + 1 +1 +1 ) ) ) − 1 -1 1
t o t = = 0 tot == 0 tot==0,说明匹配成功 r e s u l t + + result++ result++


对于 ? ? ?就麻烦一点了
t o t > 0 tot>0 tot>0,表示需要右括号匹配,使 ? ? ?为右括号,
因为右括号一定可以改为左括号(期待后面能够匹配成功),
因此 c h a n g e + + change++ change++ c h a n g e change change为可以修改为左括号的 ? ? ?个数)

t o t < 0 tot<0 tot<0 ? ? ?只能为左括号,并且不能计入num
在这里插入图片描述


如果某一个时刻, t o t < 0 , n u m > 0 tot<0,num>0 tot<0,num>0,说明可以将之前的右括号改为左括号,则 t o t + = 2 , n u m − − tot += 2,num-- tot+=2,num

剪枝部分:若 t o t < 0 , n u m = 0 tot<0,num=0 tot<0,num=0,说明此序列当前及以后都不会合法,直接 b r e a k break break

code

#include <cstdio>
#include <cstring>
#define MAXN 5005
char s[MAXN];
int result, tot, change;

int main() {
	scanf ( "%s", s );
	int len = strlen ( s );
	for ( int i = 0;i < len;i ++ ) {
		tot = 0, change = 0;
		for ( int j = i;j < len;j ++ ) {
			if ( s[j] == '(' )
				tot ++;
			else if ( s[j] == ')' ) 
					tot --;
				else {
					if ( tot > 0 )
						tot --, change ++;
					else
						tot ++;
				}
			if ( tot < 0 && change > 0 )
				tot += 2, change --;//°Ñ֮ǰµ±³É')'ÌṩµÄ-1¼Ó»ØÀ´ÔÙ¼ÓÉÏ'('µÄ¹±Ï× 
			if ( tot < 0 && ! change )
				break;
			if ( ! tot )
				result ++;
		}
	}
	printf ( "%d", result ); 
	return 0;
}

T4:Congruence Equation

题目

题目

题解

对于这种数论题只想说一句:不康题解:这神马玩意儿;康完题解:太水了
在这里插入图片描述


n ∗ a n ≡ b ( m o d   p ) n*a^n≡b(mod\ p) nanb(mod p),加上费马那一堆人的鬼定理
我们知道第一个乘数 n n n的循环节是 p p p
而指数 n n n的循环节是 φ ( p ) φ(p) φ(p),又因为 p p p为质数,所以 φ ( p ) = p − 1 φ(p)=p-1 φ(p)=p1
综上 n ⋅ a n n⋅a^n nan有循环节 p ∗ ( p − 1 ) p*(p−1) p(p1)


然后就可以设 n = j ∗ ( p − 1 ) + i n=j*(p-1)+i n=j(p1)+i,接着开始搞事
n ∗ a n ≡ b ( m o d   p ) n*a^n≡b(mod\ p) nanb(mod p)
( j ∗ ( p − 1 ) + i ) ∗ a j ∗ ( p − 1 ) + i ≡ b ( m o d   p ) (j*(p-1)+i)*a^{j*(p-1)+i}≡b(mod\ p) (j(p1)+i)aj(p1)+ib(mod p)
( j ∗ p − j + i ) ∗ a i ≡ b ( m o d   p ) (j*p-j+i)*a^i≡b(mod\ p) (jpj+i)aib(mod p)
( i − j ) ∗ a i ≡ b ( m o d   p ) (i-j)*a^i≡b(mod\ p) (ij)aib(mod p)
j ≡ i − b a i ( m o d   p ) j≡i-\frac{b}{a^i}(mod\ p) jiaib(mod p)
然后就可以枚举 i i i解出 j , n j,n j,n搞到一个最小解,根据循环节算有几个
x − m i n n p ⋅ ( p − 1 ) \frac{x−minn}{p⋅(p−1)} p(p1)xminn

code

#include <cstdio>
#define int long long
int a, b, p, x, result;

int qkpow ( int x, int y ) {
	int ans = 1;
	while ( y ) {
		if ( y & 1 )
			ans = ans * x % p;
		x = x * x % p;
		y >>= 1;
	}
	return ans;
}

signed main() {
	scanf ( "%lld %lld %lld %lld", &a, &b, &p, &x );
	for ( int i = 1;i < p;i ++ ) {
		int j = ( i - b * qkpow ( qkpow ( a, i ), p - 2 ) % p + p ) % p;
		int minx = j * ( p - 1 ) + i;
		if ( minx <= x )
			result += ( x - minx ) / ( p * ( p - 1 ) ) + 1;
	}
	printf ( "%lld", result );
	return 0;
} 

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值