How to AK ABC247
__vector__ · · 个人记录
前言:
整了一周的 whk ,总算能写写代码了。
A - Move Right
签到题
B-Unique Nicknames
这道题虽然也是一个
C-1 2 1 3 1 2 1
这道题直接按照题目模拟即可,签到题 (然而我犯智障吃了一个罚时)
D-Cylinder
这道题还是签到题。
可以定义一个结构体,用来存储连续的一段写有相同数字的球,如下:
struct Node
{
int sum,val;
}node[maxn];
sum 代表当前段的球数,val 代表当前段的球上面的数字。
将 node 作为一个栈,加入新的球时,如果新加入的那些球与栈顶的数字相同,那么将它们合并,否则将新加入的球作为一个新的栈顶元素加入栈中。
删除球的时候也差不多,就不说了。
E-Max Min
暴力肯定都会,来说一说如何对暴力进行优化,使其复杂度降为
- 数组中有一部分元素大于
x ,或小于y ,这些元素的存在实际上把数组分成了几个有效的区间。因为任何区间都不可能包含这些元素,所以可以先利用这些元素把数组划分成几个独立的区间。显然,这些区间可以单独计算答案,不会互相干扰,不会互相干扰的原因是如果要干扰肯定需要经过那些 (大于x ,或小于y ) 的元素,但这是不可能的。 - 划分完区间之后,就可以对每个区间从左到右枚举
l ,每次加上r 的取值范围大小即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace Main
{
typedef long long ll;
const int maxn=2e5+5;
int a[maxn];
int sta[maxn];
int top=0;
int n,x,y;
ll get_ans()
{
int j=1;
int cnt_x,cnt_y;
cnt_x=cnt_y=0;
ll ans=0;
for(int i=1;i<=top;i++)
{
for(;j<=top&&(cnt_x==0||cnt_y==0);j++)
{
if(sta[j]==x)cnt_x++;
if(sta[j]==y)cnt_y++;
}
if(cnt_x&&cnt_y)
{
//此时j-1为r的最小取值
ans+=(ll)(top-j+2);
}
if(sta[i]==x)cnt_x--;
if(sta[i]==y)cnt_y--;//l向右移动,清除当前
}
return ans;
}
void main()
{
scanf("%d%d%d",&n,&x,&y);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
ll out=0;
int i=1;
while(i<=n)
{
top=0;
for(;i<=n&&(a[i]<=x)&&(a[i]>=y);i++)
{
sta[++top]=a[i];
}
if(top)
{
out+=get_ans();
}
else
{i++;}
}
cout<<out;
}
}
signed main()
{
Main::main();
#ifndef ONLINE_JUDGE
system("pause");
#endif
return 0;
}
F - Cards
我是照着
考虑把每对
可以提前预处理出连通块大小为
-
f_1 = 1,f_2=3 -
f_i = f_{i-1}+f_{i-2} (i \ge 3) 最后答案就是所有连通块方案数相乘