a个1块钱,b个2块钱,问不能凑出的钱的最小值是多少
- a = 0时输出1
- a != 0时输出
a + 2 * b + 1
//Work by: Chelsea
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d %d",&n,&m)
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
int n, m, k, op;
int x, y, z;
ll a, b, c;
string s, t;
int tr[MAX];
void work(){
cin >> a >> b;
if(a == 0)cout << 1 << endl;
else{
cout << a + b * 2 + 1 << endl;
}
}
int main(){
io;
int tt;cin>>tt;
for(int _t = 1; _t <= tt; ++_t){
work();
}
return 0;
}
n种糖果,每种糖果有
a[i]
个,你每次吃糖果都会挑当前数量最多的一个糖果吃,问能不能找到一种序列 s [ 1 ] , s [ 2 ] . . . s [ ∑ i = 1 n a [ i ] ] s[1],s[2]...s[\sum_{i=1}^{n}{a[i]}] s[1],s[2]...s[∑i=1na[i]],对于所有的i
满足s[i] != s[i + 1]
我们只需要比较最大的值与次大的值的差即可,如果差大于1,则不可能满足,如果差小于等于1,那就会一直吃这两个,直达数量到达第三大的那个数,就一直这么下去
注意特判
n=1
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d %d",&n,&m)
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
int n, m, k, op;
int x, y, z;
ll a, b, c;
string s, t;
int tr[MAX];
void work(){
cin >> n;
for(int i = 1; i <= n; ++i)cin >> tr[i];
if(n == 1){
if(tr[1] > 1)cout << "NO\n";
else cout << "YES\n";
return;
}
sort(tr + 1, tr + 1 + n);
if(tr[n] - tr[n - 1] <= 1)cout << "YES\n";
else cout << "NO\n";
}
int main(){
io;
int tt;cin>>tt;
for(int _t = 1; _t <= tt; ++_t){
work();
}
return 0;
}
给你一个字符串,你可以删掉若干个字符串,使的终串满足:
- 长度为偶数
a[i] = a[i + 1], i%2=1
问最少删多少个字符?
开一个26维的数组记录每种字符出现的位置
枚举每个字符
s[l]
,用二分找到她下一个的位置r
,如果不存在r
,说明这个字符该删掉了,否则我们就计算一下[l + 1, r - 1]
中是否存在至少一对能匹配的字符,如果存在,我们就删掉当前字符s[l]
,如果不存在,我们就删掉[l 1, r - 1]
中所有的字符,更新位置再继续找用二分写起来有很多细节需要注意
//Work by: Chelsea
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d %d",&n,&m)
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
int n, m, k, op;
string s, t;
vector<int>tr[30];
inline int getpos(int id, int x){
int pp = (int)(upper_bound(tr[id].begin(), tr[id].end(), x) - tr[id].begin());
if(pp >= tr[id].size() || tr[id][pp] <= x)return -1;
else return tr[id][pp];
}
bool judge(int l, int r){
for(int ll = l; ll <= r; ++ll){
int id = s[ll] - 'a' + 1;
int rr = getpos(id, ll);
if(rr <= r && rr > l)return true;
}
return false;
}
void work(){
for(int i = 1; i <= 26; ++i)tr[i].clear();
cin >> s;n = (int)s.size();s = " " + s;
for(int i = 1; i <= n; ++i){
tr[s[i] - 'a' + 1].push_back(i);
}
int ans = 0;
for(int l = 1; l <= n;){
int id = s[l] - 'a' + 1;
int r = getpos(id, l);
if(r == -1 || judge(l + 1, r - 1)){
++ans;
++l;
}
else{
ans += r - l - 1;
l = r + 1;
}
}
cout << ans << endl;
}
int main(){
io;
int tt;cin>>tt;
for(int _t = 1; _t <= tt; ++_t){
work();
}
return 0;
}
给定一个数组,数组的元素的大小输出
[-2, 2]
的区间,你可以删任意长度的前缀,和任意长度的后缀,要求剩下的那部分的数字乘积最大,问删除的前缀和后缀的长度可以是多少
显然,0我们肯定不选,所以我们可以根据0,将长度为n的区间分成若干个不包含0的区间,求这若干个区间的最大值即可
我们需要开一个符号的前缀和数组记录负号出现的次数,用来判断区间值的乘积的正负号,还需要一个前缀和数组记录出现的绝对值是2的数量,因为值域是
[-2, 2]
,所以能让乘积变大的只能是正负2,我们就统计下来,方便查询区间的2的数量对于每个区间:
- 如果当前区间的符号是正的,就不用管,更新最大值就行
- 否则,说明需要删掉一个负数,才能变成正的,我们可以考虑删当前区间的第一个负数,或者是最后一个负数,然后来更新最大值
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d %d",&n,&m)
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef pair <int,int> pii;
#define MAX 300000 + 50
int n, m, k, op;
int tr[MAX];
int fu[MAX];
int _2[MAX];
vector<int>zero;
int ans, ansl, ansr;
int getfu_from_fornt(int x){
for(int i = x; i <= n; ++i){
if(tr[i] < 0)return i;
}
return -1;
}
int getfu_from_back(int x){
for(int i = x; i >= 1; --i){
if(tr[i] < 0)return i;
}
return -1;
}
void cal(int l, int r){
if(l > r)return;
if((fu[r] - fu[l - 1]) % 2 == 0){
if(ans < _2[r] - _2[l - 1]){
ans = _2[r] - _2[l - 1];
ansl = l;ansr = r;
}
}
else{
int ll = l, pos = getfu_from_fornt(l);
int rr = pos - 1;
if(ll <= rr && rr >= l && rr <= r && ll >= l && ll <= r){
if(ans < _2[rr] - _2[ll - 1]){
ans = _2[rr] - _2[ll - 1];
ansl = ll;ansr = rr;
}
}
ll = pos + 1;rr = r;
if(ll <= rr && rr >= l && rr <= r && ll >= l && ll <= r){
if(ans < _2[rr] - _2[ll - 1]){
ans = _2[rr] - _2[ll - 1];
ansl = ll;ansr = rr;
}
}
pos = getfu_from_back(r);
ll = l;rr = pos - 1;
if(ll <= rr && rr >= l && rr <= r && ll >= l && ll <= r){
if(ans < _2[rr] - _2[ll - 1]){
ans = _2[rr] - _2[ll - 1];
ansl = ll;ansr = rr;
}
}
ll = pos + 1;rr = r;
if(ll <= rr && rr >= l && rr <= r && ll >= l && ll <= r){
if(ans < _2[rr] - _2[ll - 1]){
ans = _2[rr] - _2[ll - 1];
ansl = ll;ansr = rr;
}
}
}
}
void work(){
cin >> n;
for(int i = 0; i <= n; ++i)_2[i] = fu[i] = 0;
zero.clear();
ans = ansl = ansr = 0;
for(int i = 1; i <= n; ++i){
cin >> tr[i];
if(tr[i] == 2 || tr[i] == -2)_2[i] = 1;
if(tr[i] == 0)zero.push_back(i);
else if(tr[i] < 0)fu[i] = 1;
fu[i] += fu[i - 1];
_2[i] += _2[i - 1];
}
if(zero.empty()){
cal(1, n);
}
else{
cal(1, zero.front() - 1);
for(int i = 0; i < zero.size() - 1; ++i){
cal(zero[i] + 1, zero[i + 1] - 1);
}
cal(zero.back() + 1, n);
}
if(ans == 0)cout << n << ' ' << 0 << endl;
else cout << ansl - 1 << ' ' << n - ansr << endl;
}
int main(){
io;
int tt;cin>>tt;
for(int _t = 1; _t <= tt; ++_t){
work();
}
return 0;
}
给你一个
n*n
的矩阵,矩阵上只有0和1,你可以将整个矩阵的所有列进行右移,最后一列移到第一列的位置去,可以将整个矩阵的所有列左移,第一列移动到最后一列去,同样的,行也类似你可以将矩阵上任意一个点的值反转,0变1,1变0,问先进行若干次轮转后,再最小需要进行多少次反转,才能让矩阵变成一个单位矩阵(主对角线全是1,其他全是0)
先不考虑轮转,一个01矩阵要变成单位矩阵,需要的花费应该是:(所有的1的数量 + 对角线上0的数量 - 对角线上1的数量)
所以我们要让对角线上1的数量最大化
轮转的结果其实不会改变行列中1的数量,进行轮转操作只是会选择哪条对角线,所以我们可以枚举每条对角线,求数量最大的1即可
为了方便枚举,我们可以复制一个完全一样的矩阵放到旁边:
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d %d",&n,&m)
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 4000 + 50
int n, m, k, op;
char tr[MAX][MAX];
void work(){
cin >> n;
int ans = 0;
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
cin >> tr[i][j];tr[i][j + n] = tr[i][j];
if(tr[i][j] == '1')++ans;
}
}
int p = 0;
for(int i = 1; i <= n; ++i){
int num = 0;
int y = i;
for(int j = 1; j <= n; ++j){
if(tr[j][y] == '1')++num;
++y;
}
p = max(p, num);
}
cout << ans + n - 2 * p << endl;
}
int main(){
io;
int tt;cin>>tt;
for(int _t = 1; _t <= tt; ++_t){
work();
}
return 0;
}
给定一个字符串,字符串只有正负号两种字符,每两个相邻的负号可以变成一个正号,问存在多少个子串,满足正负号数量匹配
easy版本的
n
数量很小,我们可以枚举左端点去找符合条件的右端点假设当前有
a
个+
,b
个-
,且是匹配成功的,那一定存在一个数字p
,满足 b − 2 ∗ p = a + p b - 2 * p = a + p b−2∗p=a+p,也就是 b − a = 3 ∗ p b - a = 3 * p b−a=3∗p,所以当(b - a) % 3 == 0 && b >= a
时可以匹配成功,暴力算就行
#include
using namespace std;
#define endl '\n'
#define inf 0x3f3f3f3f
#define mod7 1000000007
#define mod9 998244353
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define debug(a) cout << "Debuging...|" << #a << ": " << a << "\n";
typedef long long ll;
typedef pair <int,int> pii;
#define MAX 300000 + 50
int n, m, k;
char tr[MAX];
void work(){
cin >> n;
int a, b;
for(int i = 1; i <= n; ++i){
cin >> tr[i];
}
int ans = 0;
for(int i = 1; i <= n; ++i){
a = b = 0;
for(int j = i; j <= n; ++j){
if(tr[j] == '+')++a;
else ++b;
if((b - a) % 3 == 0 && b >= a){
// cout << i << ' ' << j << endl;
++ans;
}
}
}
cout << ans << endl;
}
int main(){
io;
int t;cin>>t;while(t--)work();
return 0;
}
和上面一样,不过n的范围变成了
2e5
还是利用我们上面推到的东西:
(b - a) % 3 = 0 && b >= a
我们用一个前缀和记录
b-a
的数量现在转换成存在多少对
(l, r)
,满足 s u m [ r ] − s u m [ l − 1 ] > = 0 sum[r] - sum[l-1]>=0 sum[r]−sum[l−1]>=0且 ( s u m [ r ] − s u m [ l − 1 ] ) m o d 3 = 0 (sum[r] - sum[l - 1]) mod 3 = 0 (sum[r]−sum[l−1])mod3=0即在
mod3
下,满足sum[r] = sum[l - 1], (l < r)我们可以开三个树状数组,代表模数0,1,2
然后对于每个值
sum[i]
,我们可以去对应的(sum[i]%3+3)%3
的树上去查小于等于sum[i]
的数量即可因为存在负数且树状数组不能给0进行插入和查询,所以我们需要给每个
sum[i] + n + 1
还有就是要初始化一下模数为0的0的位置,即
0 + n + 1
的位置
#include
typedef long long ll;
using namespace std;
int t,n,tr[3][800005];
char s[200005];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int op)
{
for(; x<=n+n + 1; x+=lowbit(x))
tr[op][x]++;
}
int getsum(int x,int op)
{
int ans=0;
for(;x>0;x-=lowbit(x))
ans+=tr[op][x];
return ans;
}
int main()
{
cin>>t;
while(t--)
{
int x=0;ll ans=0;
cin>>n>>(s+1);
for(int i=0;i<=2*n + 1;i++)tr[0][i]=tr[1][i]=tr[2][i]=0;
update(n,0);
for(int i=1; i<=n; i++)
{
x += (s[i]=='+'?-1:1);
ans+=getsum(x+n+1,(x%3+3)%3);
update(x+n+1,(x%3+3)%3);
}
cout<<ans<<endl;
}
return 0;
}