一个半小时七道题,两个小时一道题555;
G题鲨我;
差分
即在区间左端点标记+1,右端点标记-1;
遍历所有可行范围,遇到+1即计数值+1,-1亦然;
处理好开闭问题后,计数值为0的位置即没有被线段覆盖;
#include
using namespace std;
typedef long long ll;
int main()
{
int a[102],n,m,l,r,i;
while(~scanf("%d",&m))
{
memset(a,0,sizeof a);
scanf("%d",&n);
while(m--)
{
scanf("%d%d",&l,&r);
a[l-1]++,a[r]--;
}
queue<int>que;
int c=a[0];
for(i=1;i<=n;i++)
{
if(!c)que.push(i);
c+=a[i];
//printf("*");
}
printf("%d\n",que.size());
while(que.size())
{
printf("%d%c",que.front(),que.size()-1?' ':'\n');
que.pop();
}
}
return 0;
}
gcd
要求从第一个工作开始时间开始,所有工作开始时间均响铃,即求所有工作开始时间与第一次工作开始时间的差的最大公倍数;
再遍历所有可行响铃间隔,找出第一个满足条件的即可;
#include
using namespace std;
typedef long long ll;
int main()
{
int n,m,i;
ll del=0,g,mk;
cin>>n>>m;
cin>>mk;
for(i=1;i<=n-1;i++)
{
scanf("%lld",&g);
g-=mk;
if(!del)del=g;
else del=__gcd(del,g);
}
for(i=1;i<=m;i++)
{
scanf("%lld",&g);
if(del%g==0)break;
}
if(i<=m)printf("YES\n%d\n",i);
else printf("NO\n");
return 0;
}
对于这个数据量,模拟的话大概会爆TLE,于是我打算记录累计减去的值;
在代码中,这个值即为del;
原题中所求的最小非零值即为最小的大于del的值;
再累加减去的值即可(注意每次减去的值不是找到的数本身,而是找到的数减去该次del值);
#include
using namespace std;
typedef long long ll;
int main()
{
ll del=0,a[100005]={
0};
int n,k,i;
cin>>n>>k;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
//printf("%d\n",&a[3]);
while(k--)
{
ll *p=upper_bound(a+1,a+n+1,del);
// printf("%d %d %lld\n",p,a+n+1,del);
if(p==a+n+1)printf("0\n");
else printf("%lld\n",*p-del),del+=*p-del;
}
return 0;
}
bfs
大致估计了一下,对于目标块每一个点进行 n 2 n^2 n2遍历时间复杂度也遭得住,也没想到比较好的办法进一步降低时间复杂度,于是做得比较暴力;
对于起始点进行正常的bfs形成起始块,如果目标点已达,则输出0;
否则对目标点bfs,再对连通块中的每一个点算出距离起始块对应最近点的距离;
os:竟然在字符串处理上栽了一发;
#include
using namespace std;
typedef long long ll;
int c=1,n;//这道题代码贼乱,有两个bfs函数和一个求距离函数
int mp[51][51]={
0},gt[51][51]={
0};
void bfs(int xi,int xj)
{
int di[]={
0,0,1,-1},dj[]={
1,-1,0,0};
gt[xi][xj]=c;
int ct=1;
queue<pair<int ,int> >que;
que.push({
xi,xj});
while(!que.empty())
{
pair<int,int>now=que.front();
que.pop();
for(int k=0;k<4;k++)
{
if(now.first+di[k]>=1&&now.first+di[k]<=n
&&now.second+dj[k]>=1&&now.second+dj[k]<=n
&&mp[now.first+di[k]][now.second+dj[k]]
&&!gt[now.first+di[k]][now.second+dj[k]])
que.push({
now.first+di[k],now.second+dj[k]})
,gt[now.first+di[k]][now.second+dj[k]]=c,ct++;
}
}
c++;
//printf("%d\n",ct);
}
ll gdis(int xi,int xj)
{
ll md=100005;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(gt[i][j]==1)
{
md=min(md,(ll)(xi-i)*(xi-i)+(xj-j)*(xj-j));
}
}
return md;
}
ll bfs1(int xi,int xj)
{
int di[]={
0,0,1,-1},dj[]={
1,-1,0,0};
gt[xi][xj]=c;
int ct=1;
queue<pair<int ,int> >que;
que.push({
xi,xj});
ll mdis=gdis(xi,xj);
while(!que.empty())
{
pair<int,int>now=que.front();
que.pop();
for(int k=0;k<4;k++)
{
if(now.first+di[k]>=1&&now.first+di[k]<=n
&&now.second+dj[k]>=1&&now.second+dj[k]<=n
&&mp[now.first+di[k]][now.second+dj[k]]
&&!gt[now.first+di[k]][now.second+dj[k]])
que.push({
now.first+di[k],now.second+dj[k]})
,gt[now.first+di[k]][now.second+dj[k]]=c
,mdis=min(mdis,gdis(now.first+di[k],now.second+dj[k])),ct++;
}
}
c++;
//printf("%d\n",ct);
return mdis;
}
int main()
{
int fi,fj,ti,tj,i,j;
//char g;
cin>>n;
cin>>fi>>fj>>ti>>tj;
string g;
for(i=1;i<=n;i++)
{
cin>>g;
for(j=0;j<n;j++)
{
if(!(g[j]-'0'))mp[i][j+1]=1;
}
}
bfs(fi,fj);
if(gt[ti][tj])
{
printf("0");
}
else
{
ll ans=bfs1(ti,tj);
printf("%lld",ans);
}
return 0;
}
对于一个尖括号串,最左侧的>
右面的所有符号均可以被其消去,操作后此符号在最右端,最右侧的<
同理;
接下来为了仅剩一个符号,我们需要统计要使 以上符号出现在在对应的端点 所需要删除的符号数并取最小值;
(即对于<<<<>>><><<>
,若使最左侧的>
出现在左端,则需要删去左侧的四个<
,若使最右侧的<
出现在最右端,需要删去右侧的一个>
,故最小删去数为1)
#include
using namespace std;
typedef long long ll;
int main()
{
int t,n,i;
string g;
cin>>t;
while(t--)
{
int n;
cin>>n>>g;
if(n==1)printf("0\n");
else
{
int dl=0,dr=0;
for(i=0;g[i];i++)
{
if(g[i]=='<')dl++;
else break;
}
for(i=n-1;i>=0;i--)
{
if(g[i]=='>')dr++;
else break;
}
printf("%d\n",min(dl,dr));
}
}
return 0;
}
素数筛,模拟
模拟即可
#include
using namespace std;
typedef long long ll;
int p[10000007] , num[10000007] , pp[10000007];
int main()
{
int c=0,cc=0;
num[0]=1,num[1]=1;
for(int i=2;i<=10000000;i++)
{
if(!num[i])p[c++]=i;
for(int j=0;j<c&&i*p[j]<10000000;j++)
{
num[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
for(int i=0;i<c;i++)
{
if(!num[i+1])pp[cc++]=p[i];
}
//for(int i=0;i
int t,m;
cin>>t;
while(t--)
{
cin>>m;
int *p=lower_bound(pp,pp+cc,m);
printf("%d\n",*p);
}
return 0;
}
这个题的描述有一些些些些问题,实际上需要输出的的是以x+y为第一排序依据升序排序,以x为第二排序依据降序排序之后的第一个;
为方便描述我们将删除序列中一个元素后的序列和称为缺刻和;
对于所有的缺刻和,我们只需要记录能满足该缺刻和的所有序列中,序列号最小的两个序列号;
在对所有缺刻和寻找符合要求的x+y即可;
注:这道题个人既被卡过空间,又被卡过时间,经测试,unordered_map所用空间比map少1/10左右;
用时:1077ms/2000ms,空间占用:60236k/65535k
#include
using namespace std;
typedef long long ll;
unordered_map<int,pair<int,int> >mp;
unordered_map<int,pair<int,int> >::iterator it1;
int main()
{
int g[200005]={
0};
int k,n;
cin>>k;
for(int i=1;i<=k;i++)
{
scanf("%d",&n);
int sum=0;
for(int j=1;j<=n;j++)
{
scanf("%d",&g[j]);
sum+=g[j];
}
for(int j=1;j<=n;j++)
{
if(!mp[sum-g[j]].first)mp[sum-g[j]].first=i;
else if(!mp[sum-g[j]].second&&mp[sum-g[j]].first!=i)mp[sum-g[j]].second=i;//避免我重我自己
}
}
int f=0,mx=k+1,my=k+1;
for(it1=mp.begin();it1!=mp.end();it1++)
{
if(it1->second.first&&it1->second.second)//两个均有值才参与排序
{
int a=it1->second.first;
int b=it1->second.second;
if(a+b<mx+my||(a+b==mx+my&&b<my))//注意第二排序依据
{
mx=min(a,b),my=max(a,b);
}
}
}
if(mx!=k+1)printf("YES\n%d %d",mx,my);//mk被更新过
else printf("NO");
//printf("\n%d",mp.size());
return 0;
}
模拟
按要求模拟即可
#include
using namespace std;
typedef long long ll;
int main()
{
int t;
cin>>t;
while(t--)
{
int s,a,b,c;
cin>>s>>a>>b>>c;
ll ans=0;
ans=s/c;
ans+=b*(ans/a);
printf("%lld\n",ans);
}
return 0;
}
\