2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛
比赛链接
2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛
G.天气预报
给定一个01串,找到有多少个至少包含a个0,b个1的子串
解题思路
双指针
可以发现,对于一个位置来说,其往左满足至少有 \(a\) 个 \(0\) 且至少有 \(b\) 个 \(1\) 的位置 \(p\) 是确定的,且当前位置右移时,\(p\) 至少不会左移
- 时间复杂度:\(O(n)\)
代码
// Problem: 天气预报
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/30532/G
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int n,a,b;
LL res;
int main()
{
cin>>n>>a>>b;
string s;
cin>>s;
s=' '+s;
for(int i=1,cnt0=0,cnt1=0,l=1;i<=n;i++)
{
if(s[i]=='0')cnt0++;
else
cnt1++;
while(l<i)
{
if(s[l]=='0')
{
if(cnt0>a)l++,cnt0--;
else
break;
}
else
{
if(cnt1>b)l++,cnt1--;
else
break;
}
}
if(cnt0>=a&&cnt1>=b)res+=l;
}
cout<<res+(a==0&&b==0);
return 0;
}
L.剪绳子
题目描述
Wiki是电视节目《超级大脑》的忠实粉丝,几乎每期必看。最近节目组发明了一个新的记忆游戏,Wiki积极报名,居然成功入选了!
新的游戏规则很简单,但需要选手有超强的数字记忆能力。主持人会取来一根十米长的绳子,将它水平粘在一块平板上,则此时这根绳子可以视为一根单位为米的坐标轴,左侧一端为0,右侧一端为10。然后每隔10秒种主持人会发布一条命令,命令分两种,"剪"和"答"。如果主持人命令"剪",现场工作人员会随机在绳子上任意剪一刀(但他当然不会去剪已经剪过的地方或者剪绳子的两端)。每次剪完后绳子依然像最初那样固定在平板上,只不过剪断的地方多了一道痕迹,并且绳子的段数增加了1。此时在平板上的测量仪器会对这一次剪断位置的坐标进行测量,并将该坐标显示在屏幕上,直到主持人喊出下一次命令才会消失。由于这台仪器十分精密,它的每次测量都会精确到小数点后五位。如果主持人喊出"答",则屏幕上会随机显示一个坐标(也是保留五位小数),要求Wiki在10秒内答出该坐标目前所在的一段绳子有多长。这里保证屏幕上的数字不会出现刚才剪断过的位置坐标。
Wiki对自己的记忆力信心满满,因此接受了挑战。但他很快发现这个游戏没有那么简单,大量的数字很容易被搞混,因此求助于拥有高超编程技能的你。
输入描述:
第一行输入一个正整数q,表示主持人有q个命令。
接下来q行,每行输入一条命令。命令有两种格式:
-
C f:f是一个浮点数,且严格保留五位小数。该命令表示主持人要求现场工作人员剪绳子,并且屏幕上显示剪断位置的坐标为f;
-
A f:f是一个浮点数,且严格保留五位小数。该命令表示屏幕上显示了一个数f,要求Wiki回答出f所在的一段绳子长度为多少。这里要求"一段绳子"左右端点都是被剪断过的位置或者是初始绳子的左右端点之一(即坐标0.00000和10.00000的位置),且这一段绳子内部没有被剪断过的地方。
输出描述:
对于每个"答"的要求,要求输出屏幕显示的坐标所在的一段绳子的长度,保留五位小数。
示例1
输入
4
C 5.32145
A 4.00000
C 6.13745
A 6.00000
输出
5.32145
0.81600
备注:
解题思路·
并查集
将每个实数看作一个点,为了达到精度要求,共 \(10000001\) 个点,将所有点按剪的位置合并,记录每个点的集合大小,逆序处理询问,当剪操作时,合并两端,合并后表示剪操作后之前的那段就复原了,询问就输出所在集合的大小
- 时间复杂度:\(O(10^7)\)
set,二分
使用set维护剪的位置,然后每次询问,找到当前位置位于哪两个剪的位置之间,两个位置之间的长度即为答案,注意有可能询问端点处的长度
- 时间复杂度:\(O(nlogn)\)
代码
- 并查集
// Problem: 剪绳子
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/30532/L
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=1e7+5;
int fa[N],n,s[N];
vector<int> v;
struct A
{
int op;
double x;
}a[100005];
int find(int x)
{
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void merge(int x,int y)
{
x=find(x),y=find(y);
fa[x]=y;
s[y]+=s[x];
}
int main()
{
cin>>n;
for(int i=0;i<N;i++)fa[i]=i,s[i]=1;
for(int i=1;i<=n;i++)
{
char c;
cin>>c>>a[i].x;
a[i].op=c=='C'?1:0;
if(c=='C'&&fabs(a[i].x-0)>eps&&fabs(a[i].x-10)>eps)
v.pb(a[i].x*1000000);
}
sort(v.begin(),v.end());
for(int i=1,j=0;i<=10000000;i++)
{
if(j<v.size()&&v[j]==i)
{
// cout<<v[j]<<' ';
j++;
continue;
}
merge(i,i-1);
}
vector<int> res;
for(int i=n;i;i--)
{
if(a[i].op)merge(a[i].x*1000000,a[i].x*1000000-1);
else
res.pb(s[find(a[i].x*1000000)]);
}
for(int i=res.size()-1;i>=0;i--)printf("%.5lf\n",res[i]/1000000.);
return 0;
}
- set
// Problem: 剪绳子
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/30532/L
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
#define eps 1e-8
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int t;
set<int> s;
int main()
{
s.insert(0);
s.insert(10000000);
for(cin>>t;t;t--)
{
char op;
double x;
cin>>op>>x;
if(op=='C')s.insert(x*1000000);
else
{
if(fabs(x)<eps||fabs(x-10.)<eps)
{
if(fabs(x)<eps)printf("%.5lf\n",*(++s.begin())/1000000.);
else
{
auto p=--s.end();
auto pp=--p;
printf("%.5lf\n",(10000000-(*pp))/1000000.);
}
continue;
}
auto t=s.lower_bound(x*1000000);
auto tt=t;
tt--;
printf("%.5lf\n",((*t)-(*tt))/1000000.);
}
}
return 0;
}