作者: fn
背景
由于某些众所周知的原因,网络赛重赛了。所以这是网络赛“第一场”。
目录
- 签到题
- 1001题 Cut The Wire / 切电线
- 基本题
- 1009题 Command Sequence / 指令序列
- 1006题 Power Sum / 平方和
- 1002题 Time-division Multiplexing / 时分多路转换
签到题
1001题 Cut The Wire / 切电线
题目大意
有一条只有起点,没有终点,无限长的路。有无数的路灯,编号从1(起点)到无穷。 路灯是用电线连接的,有一条法则:
对于路灯x, 如果x是偶数,则 与 用导线连接; 如果x是奇数,那么 和
站在路灯 和 的中间,切断所有经过的电线。 也就是说,他将切断所有 和
考察内容
数学
分析
对n左侧的所有x,分奇偶 计算。
偶数x,数量为 。
奇数x,第一根和n的右边有连接的 x 为
#include<bits/stdc++.h>
using namespace std;
long long n,ans=0,x,d;
int main()
{
int t; scanf("%d",&t);
while(t--)
{
ans=0;
scanf("%lld",&n);
ans=ans+(n+1)/2; // 偶数部分
// 奇数部分
x=(n-1)/3+1;
if(x%2==1){
ans+=(n-x)/2+1;
}
else{
ans+=(n-x+1)/2;
}
printf("%lld\n",ans);
}
}
基本题
1009题 Command Sequence / 指令序列
题目大意
有一种机器人可以通过接收一系列命令来移动。
命令序列中有四种类型的命令:
U:机器人向上移动一个单位。
D:机器人向下移动一个单位。
L:机器人向左移动一个单位。
R:机器人向右移动一个单位。
现在,给定一个长度为 ( ) 的命令序列。你需要找出命令序列中有多少连续子串,满足机器人执行子字符串命令时可以返回到起始位置。
考察内容
前缀和,map
分析
前缀和预处理当前位置出现的次数。向左右可以看作向上下走了1e6。
把每个位置当作子串结尾进行遍历,每次遍历到时,ans累计map之前的值。
最后输出ans即可。
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
map<long long,long long>m;
long long t,n,v,z,ans;
char c[200005];
int main() {
scanf("%lld",&t);
while(t--) {
scanf("%lld",&n);
scanf("%s",c);
v=0;
ans=0;
m.clear();
m[0]=1;
for(int i=0;i<n;i++) {
if(c[i]=='U') {
z=1;
} else if(c[i]=='D') {
z=-1;
} else if(c[i]=='L') {
z=1e6;
} else if(c[i]=='R') {
z=-1e6;
}
v+=z;
ans+=m[v];
m[v]=m[v]+1;
}
printf("%lld\n",ans);
}
return 0;
}
1006题 Power Sum / 平方和
题目大意
给定正数 ,
求一个长度为 的数组 ,使
考察内容
思维,构造
分析
所以
时,构造 为
#include<bits/stdc++.h>
#define ll long long
#define cer(x) cerr<<(#x)<<" = "<<(x)<<'\n'
using namespace std;
const int N=1e6+10;
ll n,m,a[N];
string s;
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int t; cin>>t;
while(t--){
cin>>n;
if(n%4==1){
cout<<n<<endl;
cout<<'1';
for(int i=1;i<=n/4;i++){
cout<<"1001";
}
cout<<endl;
}
else if(n%4==2){
cout<<n+2<<endl;
cout<<"0001";
for(int i=1;i<=n/4;i++){
cout<<"1001";
}
cout<<endl;
}
else if(n%4==3){
cout<<n-1<<endl;
cout<<"01";
for(int i=1;i<=n/4;i++){
cout<<"1001";
}
cout<<endl;
}
else if(n%4==0){
cout<<n<<endl;
for(int i=1;i<=n/4;i++){
cout<<"1001";
}
cout<<endl;
}
}
return 0;
}
1002题 Time-division Multiplexing / 时分多路转换
题目大意
给定一个小写字母组成的字符串,求最短的包含其中所有字母的连续子串的长度。
考察内容
双指针
分析
首先记录总字符个数。
跑一遍双指针。右指针指向子串末尾,不断右移。当出现的不同字符个数等于总字符个数时,更新答案,然后指向子串头部的左指针右移。
复杂度
在双指针部分,注意控制一下边界情况,不要产生数组越界。
#include<bits/stdc++.h>
#define ll long long
#define cer(x) cerr<<(#x)<<" = "<<(x)<<'\n'
using namespace std;
const int N=110;
ll n,m;
string s[N];
int len[N];
int num[27];
int has[27];
int kind=0,tp;
ll gcd(ll a, ll b){
return b == 0 ? a : gcd(b, a % b);
}
void init(int n){
memset(has,0,sizeof(has));
memset(num,0,sizeof(num));
memset(len,0,sizeof(len[0])*(n+1));
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int t; cin>>t;
while(t--){
cin>>n;
init(n);
for(int i=1;i<=n;i++){
cin>>s[i];
len[i]=s[i].size();
for(int j=0;j<len[i];j++){
int t1=s[i][j]-'a';
has[t1]=1; //
}
}
kind=0;
for(int i=0;i<26;i++){
if(has[i]) kind++;
}
ll high=1;
for(int i=1;i<=n;i++){
high=(high*len[i])/gcd(high,len[i]);
}
// high<=27720,即(5*7*8*9*11)
string str; //
for(int i=0;i<high;i++){ //
for(int j=1;j<=n;j++){
int t2=i%len[j];
str += s[j][t2];
}
}
str+=str; // 两倍
ll ans=1e9+10;
ll p1=0,p2=0; //
int t3=str[p2]-'a';
num[t3]++; //
tp=1;
int F1=0;
int len2=high*n*2; //
while(p1<len2 && p2<len2){ //
if(tp==kind){ //
ans=min(ans,p2-p1+1);
if(ans<=kind){ //
cout<<ans<<endl;
F1=1;
break;
}
int t4=str[p1]-'a';
num[t4]--;
if(num[t4]==0)tp--;
p1++;
}
else{
p2++;
if(p2>=len2) break; // 防止数组越界
int t5=str[p2]-'a';
if(num[t5]==0)tp++;
num[t5]++;
}
}
if(F1==0){
cout<<ans<<endl;
}
}
return 0;
}