2021CCPC online网络赛8.28题解
2021CCPC online网络赛
1001、Cut The Wire
签到题,按照题意来思考就行
开题时间:0:05
交题时间:0:39
问题:手速慢了,其次就是思考分类时过于复杂了,但又不能快速想清楚
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
ll n;
cin>>n;
if (n%2==0)//偶数
{
ll even=ceil(n/2.0);
ll t=ceil((n-1)/3.0);
if (t%2==0) t+=1;
if (3*t+1==n) t+=1;
ll odd=(n-1-t)/2+1;
cout<<even+odd<<endl;
}
else
{
ll even=ceil(n/2.0);
ll t=ceil((n-1)/3.0);
if (t%2==0) t+=1;
ll odd=(n-t)/2+1;
cout<<even+odd<<endl;
}
}
return 0;
}
1002、Time-division Multiplexing
开题时间:2:000前后
标签:字符串、双指针、滑动窗口
相关题:
难点:读题,转化题意(出题人也说这题难点在于转化题意)
赛中出现的问题:读题太慢,没选取正确的代码(原来是二分),导致一直TLE,误以为是构造串的地方出了锅,这题拖延了整体比赛节奏
题意
这一题有一定的工科背景,大概含义就是,n行字符串都有一个指针,每次从第一行到最后一行取当前指针下标的字符,并且将指针后移一位,当指针指向了行末的下一位,那就回到0下标,依次重复构成一个循环串,求一个最短子串的长度,该串能包含所有出现过的字符。
思路
用双指针来解决最短子串,右指针每次放入,当左右指针的区间内包含的不同字符数等于所有出现过的字符数,那么就更新答案,左指针向右
重点:构造出来的串需要s+=s,原因是我们的答案,会出现在两个串交界的地方,这也是比赛时没想到的地方
代码
#include <bits/stdc++.h>
using namespace std;
string str[105];
int p[105], n;
int leng[105];
const int INF=0x3f3f3f3f;
bool fun()
{
for (int i = 1; i <= n; i++)
if (0 != p[i])
return false;
return true;
}
int vis[30];
int main()
{
ios::sync_with_stdio(false);
int T;
cin >> T;
while (T--)
{
cin >> n;
int maxn = -1, pos;
string s = "";
int gcd;
for (int i = 1; i <= n; i++)
{
cin >> str[i];
int len = str[i].size();
if (maxn < len)
maxn = len, pos = i;
p[i] = 0;
leng[i] = len;
}
int sum=0;
memset(vis,0,sizeof vis);
do
{
for (int i = 1; i <= n; i++)
{
int now = p[i];
p[i]++;
if (p[i] >= leng[i])
p[i] = 0;
s += str[i][now];
if (vis[str[i][now]-'a']==0)
sum++;
vis[str[i][now]-'a']=1;
}
} while (!fun());
//构造出来的字符串为s
//cout<<s<<endl<<s.size()<<endl;
s+=s;
memset(vis,0,sizeof vis);
int cnt=0,len=s.size(),res=INF;
for(int i=0,j=0;j<len;j++)
{
if (vis[s[j]-'a']==0)
cnt++;
vis[s[j]-'a']++;
while(cnt==sum)
{
res=min(j-i+1,res);
if (--vis[s[i]-'a']==0)
cnt--;
i++;
}
}
cout<<res<<endl;
}
return 0;
}
1006、Power Sum
开题:0:50前后
提交:1:28
队友做的,但在思考时,想到了相邻两对平方差的和等于4这个结论,也想到了只要能特殊构造出1,2,3,再不停地加上4就可以了。(但队友手速太快了直接切了%%%)
题意
给定n,让我们通过以下式子,其中$$a_i$$可为1或者-1
得到1~k的加减平方数的和,其和等于n,求出k和$$a_i$$的结果
代码
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
int n,k=0;
cin>>n;
int cnt=n/4;
n%=4;
string str="";
if (n==1)
str="1",k=1;
else if (n==2)
str="0001",k=4;
else if (n==3)
str="01",k=2;
for(int i=0;i<cnt;i++)
str+="1001";
k+=cnt*4;
cout<<k<<endl<<str<<endl;
}
return 0;
}
1009、Command sequence
题意:
给出上下左右的指令,求有多少子串能够回到初始点
思路
说白了就是求机器人是否经过一个点一次以上,有的话那么答案就加一
向上就+1,向下-1,向左+1000007,向右-1000007
如果now出现在map中,那么就代表之前走到过这
代码
#include<bits/stdc++.h>
using namespace std;
const int M=1e6+7;
typedef long long ll;
map<ll,ll> mp;
int main(){
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
ll now=0,res=0;
mp.clear();
int n;
cin>>n;
string cmd;
cin>>cmd;
mp[0]=1;//回到起点
for(int i=0;i<n;i++)
{
if (cmd[i]=='U')
now+=1;
if (cmd[i]=='D')
now-=1;
if (cmd[i]=='L')
now+=M;
if (cmd[i]=='R')
now-=M;
res+=mp[now];
mp[now]++;
}
cout<<res<<endl;
}
return 0;
}
1011、Shooting Bricks
这道题是在比赛最后一小时才看的,当时一直在调1002题,但是我看1011通过数比较多才看了一下。第一反应就是贪心或者dp
但出于没有思路就放弃掉了
赛后补题也花了一个下午才搞明白
如果本队按照赛中的0罚时,加上1002,1011题,加3次左右的罚时,那么应该能够达到rank300左右
题意
有n行m列的砖头,每个砖块都有一个价值,每打掉一个砖就要花费一颗子弹。有些标记成'Y'的砖是不花费子弹的,求:当你有K颗子弹时,最多能得到多少价值?
思路
思路是赛后看得题解做出来的
我们将子弹花费转化成我们的背包模型的空间
先预处理一下,我们在第j列上,花费cnt颗子弹,能够得到多少的价值
vy[i][j]代表在第i列花费j时得到的恰好到'Y'的砖块
vn[i][j]代表在第i列花费j时得到的恰好到'N'的砖块
fy[i][j]代表从1到i列,在第i列上花费j颗子弹,并且恰好最后一颗打在了'Y'砖块上的最大总价值
fn[i][j]代表从1到i列,在第i列上花费j颗子弹,并且恰好最后一颗打在了'N'砖块上的最大总价值
代码
#include<bits/stdc++.h>
using namespace std;
const int N=250;
int fy[N][N],fn[N][N],a[N][N],st[N][N],vn[N][N],vy[N][N];
int main(){
ios::sync_with_stdio(false);
int T;
cin>>T;
while(T--)
{
memset(fy,0,sizeof fy);
memset(fn,0,sizeof fn);
memset(vn,0,sizeof vn);
memset(vy,0,sizeof vy);
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
char ch;
cin>>a[i][j]>>ch;
st[i][j]=(ch=='Y');
}
//预处理
for(int j=1;j<=m;j++)
{
int cnt=0;
for(int i=n;i>=1;i--)
{
if (st[i][j])
{
vy[j][cnt]+=a[i][j];
//cout<<"j:"<<j<<"cnt:"<<cnt<<" "<<vy[j][cnt]<<endl;
}
else
{
cnt++;
vn[j][cnt]=vy[j][cnt-1]+a[i][j];
vy[j][cnt]=vn[j][cnt];
}
}
}
for(int i=1;i<=m;i++)//枚举列
for(int j=0;j<=k;j++)//1~i列花费j
for(int l=0;l<=min(j,n);l++)//在第i列花费l
{
//
fy[i][j]=max(fy[i][j],fy[i-1][j-l]+vy[i][l]);
if (l==j)
fn[i][j]=max(fn[i][j],fy[i-1][j-l]+vn[i][l]);
else if (l==0)
fn[i][j]=max(fn[i][j],fn[i-1][j-l]+vy[i][l]);
else
fn[i][j]=max(fn[i][j],max(fy[i-1][j-l]+vn[i][l],fn[i-1][j-l]+vy[i][l]));
//cout<<i<<' '<<j<<' '<<k<<' '<<fn[i][j]<<endl;
}
cout<<fn[m][k]<<endl;
}
return 0;
}
后续还需要补1013,1012、Remove可能要放弃了

浙公网安备 33010602011771号