获取中...

-

Just a minute...

Codeforces Round #574 (Div. 2)

A.Drinks Choosing

就把可以凑对的凑在一起,不能的俩俩组合

B.Sport Mafia

题目思路:

算出全放糖果的sum,算出与留下糖果的差cha

可知,每少放一次就会减少N-i个糖果,i >= 1(因为不放还吃了)

cha就是少了的糖果的总和,根据等差数列求和公式

进行二分查找少放了几次,就是吃了几次

题目代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//freopen("input.in","r",stdin);
//freopen("output.out","w",stdout);
/* --------------------------------------------------------------------------------------*/
cin >> N >> M;
LL sum =(N*(1+N))/2;
LL s = sum - M;
LL l = 0;
LL r = N;
LL mid;
while(l <= r)
{
mid = (l+r)/2;
LL cha = s - mid;
LL su = (mid*(N+N-mid+1))/2;
if(cha > su)
{
l = mid+1;
}
else if(su > cha)
{
r = mid-1;
}
else break;
}
cout << mid << endl;
return 0;
}

C.Basketball Exercise

题目思路:

感觉瞎写就过了,我也不知道是贪心还是dp

就保证每走一步从上下出来的时候sum是最大的,每一步有俩中走法,一种是从下面上来,一种是刚才空了一个上面没走

题目代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*-------------------------------------------------------------------------------------------*/
LL a[MAX];
LL b[MAX];
LL sum[2][MAX];
/* ------------------------------------------------------------------------------------------*/


int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//freopen("input.in","r",stdin);
//freopen("output.out","w",stdout);
/* --------------------------------------------------------------------------------------*/
cin >> N;
for(int i = 0;i < N;i++)
{
cin >> a[i];
}
for(int i = 0;i < N;i++)
{
cin >> b[i];
}
LL s[2];
s[0] = a[0];
s[1] = b[0];
for(int i = 1;i < N;i++)
{
LL u,d;
u = s[0];
d = s[1];
s[0] = max(d+a[i],u - a[i-1]+a[i]);
s[1] = max(u+b[i],d - b[i-1]+b[i]);
}
cout << max(s[0],s[1]);
return 0;
}

D.Submarine in the Rybinsk Sea (easy edition)

D2.Submarine in the Rybinsk Sea (hard edition)

题目思路:

以123 45 6为例子可以组成

112233 12435 1236

14253 4455 456

1236 66 465

首先定义一个数组ten={0,1,10,···}

每一个数字都表示为第k(自右)位的值*ten[k]

经过观察可以发现,每个数字对答案的贡献次数为2*N

还可以发现,每位上的数字贡献是相同的(*ten[i]和次数是相同的)

(看123的2,和45的4,分别2 * 1000 * 2 + 2 * 100 * 4,4 * 1000 * 2 + 4 * 100 * 4)

所以我们把每一位上的数字加起来存到sum[i]

我们还需要一个数组记录长度为k的数字有多少个len[i]

然后我们把情况分为俩种

对于第k位的贡献,可以分为俩类

1.长度>=k的数字n,为sum[k] * (ten[2 * k] + ten[2 * k - 1]) * len[i](i为n的长度)

2.长度<k的数字n,为sum[k] * ten[k + i] * 2 * len[i]

题目代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*-------------------------------------------------------------------------------------------*/
LL ten[MAX];
LL len[MAX];
LL sum[MAX];
/* ------------------------------------------------------------------------------------------*/
int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//freopen("input.in","r",stdin);
//freopen("output.out","w",stdout);
/* --------------------------------------------------------------------------------------*/
cin >> N;
string str;
LL ans = 0;
ten[1] = 1;
for(int i = 2;i <= 24;i++)
{
ten[i] = (ten[i-1]*10) % MOD;
}
int maxl = 0;
for(int i = 0;i < N;i++)
{
cin >>str;
int l = str.size();
maxl = max(maxl,l);
len[l]++;
for(int i = l-1,j = 1;i >=0;i--,j++)
{
sum[j] += (LL)(str[i] - '0');
}
}
for(int i = maxl;i > 0 ;i--)//位数
{
for(int j = maxl;j > 0;j--)
{
if(j < i) ans += ((sum[i] * ten[j+i]) % MOD) * len[j] * 2 % MOD;
else if(j == i || j > i)
{
ans += ((sum[i] * ten[2*i]) % MOD) * len[j] % MOD;
ans += ((sum[i] * ten[2*i-1]) % MOD) * len[j] %MOD;
}
}
}
cout << ans % MOD<<endl;
return 0;
}

E.OpenStreetMap

单调队列 传送门

这是一个在O(N)复杂度内在一个区间内找到子区间最小值的方法

实现单调队列的方法:

1.滑动窗口右滑。每年选拔新队员时,淘汰比这名新队员弱的老队员。对于单调队列,就是插入新元素时,把先前存在的比当前元素小的元素弹出(从队尾退队)。

2.滑动窗口右滑。只需判断最老的队员是否需要退队。对于单调队列,只需判断队头是否已经超出滑动窗口范围,若超出,则从队头退队。

3.查询滑动窗口最大值。直接派最老的队员参赛/直接返回队头元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
struct Num{
int index,x;//需要记录单调队列内每个数的入队时间(index)和大小(x)
};

int a[MAXN]; //原数组
deque<Num> q; //单调队列

int main(void){
int n,m; //n表示序列长度,m表示滑动窗口长度
Num t;//保存当前元素
//输入
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
//问题解决
for (int i=1;i<=n;i++){

//先输出数a[i]前的最小值
if (q.empty()) //q空,即a[i]前没有元素
printf("0\n");
else { //否则判断队头是否需要出队并输出范围内的队头
if (q.front().index+m<i) //队头已经超出滑动窗口范围
q.pop_front(); // 弹出队头
printf("%d\n",q.front().x); //此时队一定非空(想想为什么)
}

while ((!q.empty()) && q.back().x>=a[i])
//当队列非空时,不断弹出队尾比当前元素大的元素
q.pop_back();

t.index=i;
t.x=a[i];
q.push_back(t);//将当前元素入队
//注意:当前元素无论如何都会入队(想想为什么)
}
return 0;
}

题目思路:

题意是给你一个矩阵h(N * M),然后问你h中所有子矩阵(a * b)中的最小值的sum

首先第一步找到矩阵hij,我们可以根据题意推论出$g_0 - g_{m-1}$就是矩阵第一行,第二行从gm开始

然后我们把1-N行每一行中的区间(0,b-1)(1,b)···(M-b+1,M)的最小值找到,得到矩阵hgt

然后我们再把矩阵hgt中每一列区间(0,a-1) (1.a) ··· (N-a+1,N)的最小值找到,这里最小值就是每一个子矩阵的最小值了

找最小值就通过单调队列来找

题目代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*-------------------------------------------------------------------------------------------*/
int hgt[MAX][MAX];

/* ------------------------------------------------------------------------------------------*/


int main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
//freopen("input.in","r",stdin);
//freopen("output.out","w",stdout);
/* --------------------------------------------------------------------------------------*/
int a,b;
cin >> N >> M >> a >> b;
LL g,x,y,z;
cin >> g >>x>>y>>z;
int k;
for(int i = 1;i <= N;i++)
{
deque<pair<int,int>> q;
k = 1;
for(int j = 1;j <= M;++j)
{
while(q.size() && q.back().first >= g) q.pop_back();
while(q.size() && q.front().second < j-b+1) q.pop_front();
q.push_back({g,j});
if(j >= b)
{
hgt[i][k++] = q.front().first;
}
g = (g*x + y) % z;
}
}

LL ans = 0;
for(int j = 1;j <= M;j++)
{
deque<pair<int,int>> q;
for(int i = 1;i <= N;++i)
{
while(q.size() && q.back().first >= hgt[i][j]) q.pop_back();
while(q.size() && q.front().second < i - a+1) q.pop_front();
q.push_back({hgt[i][j],i});
if(i >= a)
{
ans += (LL)q.front().first;
}
}
}
cout << ans;
return 0;
}
相关文章
评论
分享
  • ECF-70-2

    Educational Codeforces Round 70 (Rated for Div. 2)A.You Are Given Two Binary Strings乘2^k次,其实就是把二进制左移了k位 加法就是对应位加就好了,然...

    ECF-70-2
  • CF-577-2

    Codeforces Round #577 (Div. 2)A.Important Exam问学生分数总和最大为多少 那么就是每道题选的最多的选项为答案,计算即可 B.Zero Array如果sum是奇数的一定不行 如果是偶数的话就看...

    CF-577-2
  • CF-569-2

    吹爆这一场,第一次打到这么前,虽然赛后打得 Codeforces Round #569 (Div. 2)A.Alex and a Rhombus每次增多(i-1)*4个 B.Nick and Array他的操作真正的意思就是,变负数绝...

    CF-569-2
  • CF-576-2

    Codeforces Round #576 (Div. 2)A.City Day啊,爆哭,还想着怎么能优化一下,感觉会超时 结果优化wa了,真好,那就纯暴力 对每一个a,都找到l,r判断区间符不符合条件 注意0天的时候就好 B.Wat...

    CF-576-2
  • ECF-69-2

    Educational Codeforces Round 69 (Rated for Div. 2)A.DIY Wooden Ladder找最长的的俩个,然后看是能放的木板多,还是给的木板多 B.Pillars观察发现这个序列有三种情...

    ECF-69-2
  • CF-575-3

    Codeforces Round #575 (Div. 3)A.Three Piles of Candies傻逼题,一人拿一堆,剩下一堆还能随便分,加起来除2 B.Odd Sum Segments一个序列里只有奇数个奇数时和才是奇数 ...

    CF-575-3
  • CF-571-2

    Codeforces Round #571 (Div. 2)Vus the Cossack and a Contestm,k都不小于n Vus the Cossack and Strings通过观察可以发现当字符串中’1’的数量奇偶相...

    CF-571-2
  • ECF-68-2

    Educational Codeforces Round 68 (Rated for Div. 2)Remove a Progression找到规律,隔一个删一个 Yet Another Crosses Problem这个气死了,存的...

    ECF-68-2
  • CF-559-2(未完待续)

    就学了一个lower把,先放在这里 还要学习读题23333 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748...

    CF-559-2(未完待续)
  • CF-554-2(未完待续)

    123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263...

    CF-554-2(未完待续)
Please check the parameter of comment in config.yml of hexo-theme-Annie!