1.怪怪の出行
题目大意:输入一段数列长度以及对该数列的操作次数;输入一个字符,对于ABC有不同的操作:A:输出从一到当前位置的人数和,B:第p节车厢加入m个人,C:第p节车厢下去m个人
方法一(暴力):每次输入,A:从1到当前位置暴力枚举,再累加输出;B a[p]+=m;C:a[p]-=m;
不过,方法一对于100%的数据并不能过,所以要思考better的算法
我们可以不暴力枚举,而是用一个t,ans,用来记录怪怪到上一次查询时的位置和答案,当要再一次查询,就把上一次位置之后的人到当前位置的人加在一起;当输入的时B或C时,再判断一下m和t的关系
int t=0,ans=0;
cin>>n>>k;
for(int i=1;i<=k;i++)
{
cin>>ch;
if(ch=='A'){
cin>>m;
for(int j=t+1;j<=m;j++)
ans+=a[j];
cout<<ans<<endl;
t=m;
}
if(ch=='B'){
cin>>m>>p;
if(m<=t)//上车的人在怪怪之前
ans+=p;
else a[m]+=p;
}
if(ch=='C'){
cin>>m>>p;
if(m<=t)ans-=p;//下车的人在怪怪之前
else a[m]-=p;
}
}
2.怪怪の复查
题目大意:一个长度为n的数列a,对a进行m次操作,每次给定L,R,对[L,R]区间进行加值操作,对该区间的每一个值加上1,求出最后a数列中为0的数量
方法一(暴力):按照题意模拟
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>l>>r;
for(int j=l;j<=r;j++)a[i]++;
}
for(int i=1;i<=n;i++)
if(a[i]==0)ans++;
cout<<ans<<endl;
显然,方法一并不能A
方法二:利用前缀和与差分优化
每次在a[L]加上一个k,a[R+1]减去一个k。最后做一遍前缀和,就得出新的a数列(k=1),最后在枚举一遍,值为0 ans++
#include <bits/stdc++.h>
using namespace std;
int n,m,a,b,ans=0;
int check[200010]={};
inline int read()
{
int w=1,s=0;
char ch=getchar();
while(ch<'0'||ch>'9')if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9'){
s=(s<<3)+(s<<1)+ch-'0';
ch=getchar();
}
return s*w;
}
int main()
{
n=read();
m=read();
while(m--)
{
int a=read(),b=read();
check[a]++,check[b+1]--;
}
for(int i=1;i<=n;i++)
{
check[i]+=check[i-1]
if(!check[i])ans++;
}
cout<<ans<<endl;
return 0;
}
3.怪怪の加密
题目大意:将一个字符串操作,使得该字符串任意两个相邻的字符不同
方法:栈模拟,遇到和栈顶相同的,则弹出栈顶,否则压入栈。最后从栈底按顺序导出即可
#include<bits/stdc++.h>
using namespace std;
string s;
char a[1000010]={};
int t=1;
int main()
{
// freopen("lock.in","r",stdin);
// freopen("lock.out","w",stdout);
cin>>s;
for(int i=0;i<s.size();i++)
{
if(a[t-1]==s[i])t=t-1;
else a[t]=s[i],t++;
}
for(int i=1;;i++)
if(a[i]!=0)cout<<a[i];
else return 0;
return 0;
}
4.方方方
方法一:(六重循环)(暴力)
我们可以六重循环,直接直接暴力枚举三个点的位置,再进一步算出花费,判断是否再l与r之间。(代码不再给出,思路简单明了)
优化:
在此之前,我们要分析题目。对于方格图中任意三个点,花费将是某个矩形的周长,如图
在4*8的方格图中,选(1,1),(3,4),(4,3)三个点,花费=a+b+c,即一个矩形的周长。但是,在该矩形中,其他的点也可以构成该矩形……所以,我们要think
对于i行j列的矩形,寻找三个点,应该有4*(i-2)*(j-2)+2*(i-2)*(j-2)中情况。具体过程如下
{
一个矩形,有四条边,这四条边上每条上都得有一个点,可最多只有三个点,所以至少有一个点在矩形的顶点上。接下来分两种情况:
①:
两点在顶点上,第三点在中间的矩阵。题目中说,三点之中任意两点都不在同一行同一列,所以前两点有两种情况,左上右下和左下右上,第三点在中间的小矩阵可以任意取,为(i-2)*(j-2) ∴第一种情况为2*(i-2)*(j-2)
②:
一点在顶点上,有四种情况;剩余两点在顶点不去的两边上,情况也为(i-2)*(j-2),总共有4*(i-2)*(j-2)
综上所述,对于i行j列的矩形,取三个点,有6*(i-2)*(j-2)种情况
再加上n行m列的矩形取i行j列的矩形有(n-i+1)*(n-j+1)个
所以,我们就可以以o(1)的时间得出在n*m的矩阵中,取大小为i*j的方案和
就得出了o(nm)的算法:i,j枚举矩阵大小,判断花费是否在l到r之间,如果可以,就j加上方案和,代码如下
#include<bits/stdc++.h>
using namespace std;
const long long Mo=1000000007;
long long n,m,l,r,ans=0;
inline int read()
{
int w=1,s=0;
char ch=getchar();
while(ch<'0'||ch>'9')if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9'){
s=(s<<3)+(s<<1)+ch-'0';
ch=getchar();
}
return s*w;
}
int main()
{
n=read();m=read();l=read();r=read();
for(int i=3;i<=n;i++)
for(int j=3;j<=m;j++)
{
if(i-1+j-1+i-1+j-1>=l&&i-1+j-1+i-1+j-1<=r)ans+=(4*(i-2)*(j-2)+2*(i-2)*(j-2))%Mo*(n-i+1)%Mo*(m-j+1)%Mo;
}
cout<<ans%Mo<<endl;
return 0;
}
至此,我们就可以A了这题啦,代码非常短,但过程特别艰辛,尤其是考试的时候……