A. Binary Imbalance
思路
-
- 只要有 01 或 10 01\;或\;10 01或10 存在我们就可以一直插入 0 0 0 ,所以记录 1 1 1 的数量即可,数量等于 n n n 这不存在不同-> N O NO NO,反之-> Y E S YES YES 。
signed main()
{
int T=read();
while(T--)
{
re int cnt=0;
n=read();
scanf("%s",s+1);
dfor(i,1,n) s[i]=='1'?++cnt:0;
cnt==n?puts("NO"):puts("YES");
}
return 0;
}
B. Getting Points
思路
-
- 很容易想到一天能够获得的最大收益为
t
⋅
2
+
l
t\cdot2+l
t⋅2+l ,那么这样的天数是
t
a
s
k
task
task 的二分之一,二分答案
往左,因为工作的天数越少越好最大收益。不过这个天数可能会是奇数,无碍,特判即可。
- 很容易想到一天能够获得的最大收益为
t
⋅
2
+
l
t\cdot2+l
t⋅2+l ,那么这样的天数是
t
a
s
k
task
task 的二分之一,二分答案
-
- 二分完了之后也有可能还是不到 p p p ,不过此后就靠 l l l 堆出来即可。
int n,p,l,t;
signed main()
{
int T=read();
while(T--)
{
n=read(),p=read(),l=read(),t=read();
re int d=(t<<1)+l,s=n/7+(n%7?1:0),d1=0;
if(s&1) d1=t+l;
s>>=1;
re int l1=1,r1=s,ans=s;
while(l1<=r1)
{
int mid=(l1+r1)>>1;
if(mid*d>=p) ans=mid,r1=mid-1;
else l1=mid+1;
}
if(ans*d>=p) writeln(n-ans);
else if(ans*d+d1>=p) writeln(n-ans-1);
else
{
p-=ans*d+d1;
writeln(n-p/l-(p%l?1:0)-(d1?1:0)-ans);
}
}
return 0;
}
C. Insert and Equalize
思路
-
- 最后都要变成相同的数,在不插入 a n + 1 a_{n+1} an+1 的情况下就是变成最大的数。而单位大小都是 x x x 易得最大的 x x x 就是每一个数与最大值差值的最大公约数。将序列排序,对于 a n + 1 a_{n+1} an+1 插入的位置来说插入在第一个或者最后一个对答案的贡献是一样的,需要考虑的事插入在中间的情况。我们当然希望 a n + 1 a_{n+1} an+1 越靠近最大值越好这样对答案的贡献越小。我们可以从最大值开始往前遍历,如果两个元素的差值大于 G C D GCD GCD ,那么一定可以插入在这里。如果不是插入在中间位置,那插入在最前最后都一样,我选在最前面。
int n,a[N];
int gcd(int x,int y)
{
return y?gcd(y,x%y):x;
}
signed main()
{
int T=read();
while(T--)
{
n=read();
dfor(i,1,n) a[i]=read();
if(n==1){puts("1");continue;}
sort(a+1,a+n+1);
re int GCD=a[n]-a[n-1];
dforr(i,n-1,2) GCD=gcd(GCD,a[i]-a[i-1]);
re int sum=0;
re bool f=0;
dforr(i,n,2)
{
sum+=(a[n]-a[i-1])/GCD;
if(a[i]-a[i-1]>GCD&&!f) sum+=(a[n]-a[i])/GCD+1,f=1;
}
if(f) writeln(sum);
else writeln(sum+(a[n]-a[1])/GCD+1);
}
return 0;
}
D. Robot Queries
分析
-
- 一种很简单的思路模拟出每一步的坐标,记录下来。直接询问。很显然会 T E L TEL TEL 。
-
- 规定 P i P_i Pi 是 S i S_i Si m o v e move move 后的坐标,通过手模可以发现 r e v e r s e [ l , r ] reverse\;[l,r] reverse[l,r] 之后 P 0 ∼ P l − 1 P_0\sim P_{l-1} P0∼Pl−1 坐标不变, P r ∼ P n P_r\sim P_n Pr∼Pn 坐标不变。改变的仅仅是 P l ∼ P r − 1 P_l\sim P_{r-1} Pl∼Pr−1 的坐标,而该区间的坐标改变有明显的规律关于中心对称。
思路
这题我看了官方题解代码与官方题解相似度
<
100
%
<100\%
<100%
值得一提的是
l
a
m
b
d
a
lambda
lambda 的使用是我从未接触的新大陆,现在及以后将会给我带来极大的便利
-
- 记录每一个 P i P_i Pi ,并用 m a p map map 对于每一个 P i P_i Pi 都记录其位置下标 i i i ( P i P_i Pi 视作桶,用 m a p map map 方便使用二分) 。
-
- 查询三个区间 [ 0 , l − 1 ] [ l , r − 1 ] [ r , n ] [0,l-1]\;[l,r-1]\;[r,n] [0,l−1][l,r−1][r,n] 。
-
-
[
0
,
l
−
1
]
[
r
,
n
]
[0,l-1]\;[r,n]
[0,l−1][r,n] 直接查询
x
y
x\;y
xy 即可
这两个区间坐标不变, [ l , r − 1 ] [l,r-1] [l,r−1] 查询 x y x\;y xy 关于中心对称的坐标即可。由分析可得一对关于中心对称的点对为 ( P l − 1 , P r ) (P_{l-1},\;P_r) (Pl−1,Pr) 。
-
[
0
,
l
−
1
]
[
r
,
n
]
[0,l-1]\;[r,n]
[0,l−1][r,n] 直接查询
x
y
x\;y
xy 即可
-
- 二分查询直接找大于等于左端点即可。再判断是否小于右端点。
int n,q;
char s[N];
signed main()
{
n=read(),q=read();
scanf("%s",s+1);
vector<pair<int ,int > > ve;
ve.push_back(make_pair(0,0));
dfor(i,1,n)
{
int x=ve[i-1].first+(s[i]=='R')-(s[i]=='L');
int y=ve[i-1].second+(s[i]=='U')-(s[i]=='D');
ve.push_back(make_pair(x,y));
}
map<pair<int ,int > ,vector<int > > mp;
dfor(i,0,n) mp[ve[i]].push_back(i);
auto check = [&](pair<int ,int > p,int l,int r)
{
if(!mp.count(p)) return false;
auto it=lower_bound(mp[p].begin(), mp[p].end(), l);
return it!=mp[p].end()&&*it<=r;
};
while(q--)
{
int x,y,l,r;
x=read(),y=read(),l=read(),r=read();
int xx=ve[r].first+ve[l-1].first-x,yy=ve[r].second+ve[l-1].second-y;
bool f=check({x,y},0,l-1)|check({xx,yy},l,r-1)|check({x,y},r,n);
f?puts("YES"):puts("NO");
}
return 0;
}
E. Collapsing Strings
我感觉其实比D简单
思路
-
- 求的就是当前字符串的后缀与每一个字符串的前缀的最大公共长度。我们可以用字典树记录前缀,询问时翻转字符串,上述所求就变成求字符串前缀的最大公共长度,前缀字典树即可解决。答案当然是总长度-所求。
int n,q,tot,cnt[N],trip[N][26];
void ins(string s)
{
int x,p=0;
dfor(i,0,s.size()-1)
{
x=s[i]-'a';
if(!trip[p][x]) trip[p][x]=++tot;
p=trip[p][x],++cnt[p];
}
}
int query(string s)
{
int x,p=0,ans=0;
dfor(i,0,s.size()-1)
{
x=s[i]-'a';
p=trip[p][x];
ans+=cnt[p];
if(!p) return ans;
}
return ans;
}
signed main()
{
n=read();
vector<string > ve;
string s;
int sum=0;
dfor(i,1,n)
{
cin>>s;
sum+=s.size(),ve.push_back(s);
ins(s);
}
int ans=0;
dfor(i,0,ve.size()-1)
{
reverse(ve[i].begin(),ve[i].end());
ans+=n*ve[i].size()+sum-(query(ve[i])<<1);
}
write(ans);
return 0;
}