这套题比上一套题水多了,但是写题解真的好累啊啊啊啊啊!!!
Div. 2 A Mike and Cellphone
这题只需要把拨的号码上下左右移动一下看有没有超出键盘范围就好了。
#include<bits/stdc++.h>
int main()
{
int n,i,j,x;
char c;
bool flag[6][5],flag1[6][5],flag2=true;
memset(flag,false,sizeof(flag));
memset(flag1,false,sizeof(flag1));
for (i=1;i<=3;i++)
for (j=1;j<=3;j++)
flag[i][j]=true;
flag[4][2]=true;
scanf("%d",&n);
getchar();
for (i=0;i<n;i++)
{
c=getchar();
x=c-'0';
if (x)
flag1[(x-1)/3+1][(x-1)%3+1]=true;
else
flag1[4][2]=true;
}
for (i=0;i<6;i++)
for (j=0;j<5;j++)
if (flag1[i][j])
if (!flag[i+1][j])
{
flag2=false;
break;
}
if (flag2)
{
printf("NO");
return 0;
}
flag2=true;
for (i=0;i<6;i++)
for (j=0;j<5;j++)
if (flag1[i][j])
if (!flag[i-1][j])
{
flag2=false;
break;
}
if (flag2)
{
printf("NO");
return 0;
}flag2=true;
for (i=0;i<6;i++)
for (j=0;j<5;j++)
if (flag1[i][j])
if (!flag[i][j+1])
{
flag2=false;
break;
}
if (flag2)
{
printf("NO");
return 0;
}
flag2=true;
for (i=0;i<6;i++)
for (j=0;j<5;j++)
if (flag1[i][j])
if (!flag[i][j-1])
{
flag2=false;
break;
}
if (flag2)
{
printf("NO");
return 0;
}
printf("YES");
return 0;
}
Div. 2 B Mike and Shortcuts
这道题等价于,给一棵无向树,其中仅有 (i,i+1)(i,i−1)(i,a i ) 之间有边,所有边的权为1,求编号为1的点到其余各点的最短路程。直接 SPFA 就好了。复杂度 O(n) 。
#include<bits/stdc++.h>
#define N 200010
using namespace std;
queue<int>q;
typedef struct edge
{
int next,to;
};
typedef struct point
{
int first,dis,visited;
};
edge edg[3*N];
point poi[N];
int e;
void addedge(int u,int v)
{
edg[++e].to=v;
edg[e].next=poi[u].first;
poi[u].first=e;
}
void dfs(int i)
{
int j;
poi[i].visited=true;
for (j=poi[i].first;j;j=edg[j].next)
{
if (poi[edg[j].to].dis>poi[i].dis+1)
{
poi[edg[j].to].dis=poi[i].dis+1;
q.push(edg[j].to);
}
if (!poi[edg[j].to].visited)
dfs(edg[j].to);
}
}
void bfs()
{
int i,j;
while (!q.empty())
{
for (i=q.front(),q.pop(),j=poi[i].first;j;j=edg[j].next)
if (poi[edg[j].to].dis>poi[i].dis+1)
{
q.push(edg[j].to);
poi[edg[j].to].dis=poi[i].dis+1;
}
}
}
int main()
{
int n,i,a;
scanf("%d",&n);
for (i=1;i<=n-1;i++)
{
addedge(i,i+1);
addedge(i+1,i);
}
for (i=1;i<=n;i++)
{
poi[i].dis=i-1;
poi[i].visited=false;
}
for (i=1;i<=n;i++)
{
scanf("%d",&a);
if (i!=a)
addedge(i,a);
}
dfs(1);
bfs();
for (i=1;i<=n;i++)
printf("%d ",poi[i].dis);
return 0;
}
Div. 2 C Mike and Shortcuts
一道数论题,对于每个
n
,符合要求的方案数为
#include<bits/stdc++.h>
using namespace std;
long long total(long long mid)
{
long long sum=0,i;
for (i=2;mid/(i*i*i);i++)
sum+=mid/(i*i*i);
return sum;
}
int main()
{
long long i,left,right,mid,m;
scanf("%I64d",&m);
left=0;
right=m<<3;
while (left<right-1)
{
mid=(left+right)/2;
if (total(mid)>=m)
right=mid;
else
left=mid;
}
if (total(left)==m)
printf("%I64d",left);
else
if (total(right)==m)
printf("%I64d",right);
else
printf("-1");
return 0;
}
Div. 2 D Friends and Subsequences
固定
l
之后,关于
#include<bits/stdc++.h>
using namespace std;
const int N=1<<18;
int segmax[2*N],segmin[2*N],n,a[N],b[N];
void buildmax()
{
int i;
for (i=N+n-1;i>=N;i--)
segmax[i]=a[i-N+1];
for (i=N-1;i>=1;i--)
segmax[i]=max(segmax[i*2],segmax[i*2+1]);
}
void buildmin()
{
int i;
for (i=N+n-1;i>=N;i--)
segmin[i]=b[i-N+1];
for (i=N-1;i>=1;i--)
segmin[i]=min(segmin[i*2],segmin[i*2+1]);
}
int searchmax(int left,int right)
{
int m=INT_MIN,l,r;
for (l=N+left-1,r=N+right;l<r;l/=2,r/=2)
{
if (l%2)
m=max(m,segmax[l++]);
if (r%2)
m=max(m,segmax[--r]);
}
/*cout<<left<<" max "<<right<<endl;
cout<<m<<endl;*/
return m;
}
int searchmin(int left,int right)
{
int m=INT_MAX,l,r;
for (l=N+left-1,r=N+right;l<r;l/=2,r/=2)
{
if (l%2)
m=min(m,segmin[l++]);
if (r%2)
m=min(m,segmin[--r]);
}
/*cout<<left<<" min "<<right<<endl;
cout<<m<<endl;*/
return m;
}
int main()
{
int i,j,l,r,mid,left,right;
long long ans=0;
scanf("%d",&n);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
for (i=1;i<=n;i++)
scanf("%d",&b[i]);
for (i=1;i<N<<1;i++)
{
segmax[i]=INT_MIN;
segmin[i]=INT_MAX;
}
buildmax();
buildmin();
for (i=1;i<=n;i++)
{
l=i;
r=n;
while (l<r)
{
mid=(l+r)/2+1;
if (searchmax(i,mid)<searchmin(i,mid))
l=mid;
else
r=mid-1;
}
if (searchmax(i,l)>=searchmin(i,l))
l--;
left=l;
//cout<<left<<endl;
l=i;
r=n;
while (l<r)
{
mid=(l+r)/2;
if (searchmax(i,mid)>searchmin(i,mid))
r=mid;
else
l=mid+1;
}
if (searchmax(i,l)<=searchmin(i,l))
l++;
right=l;
//cout<<right<<endl;
ans+=right-left-1;
}
printf("%I64d",ans);
return 0;
}
Div. 2 E Mike and Geometry Problem
首先用前缀和的方法来统计各点被覆盖的次数,然后把200000以内的阶乘和阶乘的数论倒数打个表用来计算组合数就好了。注意用费马小定理求数论倒数时直接硬算会超时,要用快速幂。复杂度 O(nlogn) 。
#include<bits/stdc++.h>
using namespace std;
map<long long,long long>m;
const long long N=200010;
const long long moder=1000000007;
long long n,l[N],r[N],k,fac[N],inv[N];
long long power(long long num,long long index)
{
long long i,j,bi[40],ans=1;
i=0;
while (index)
{
bi[i++]=index%2;
index/=2;
}
for (j=0;j<i;j++)
{
if (bi[j])
ans=ans*num%moder;
num=num*num%moder;
}
return ans;
}
int main()
{
long long i,k,count=0,ans=0,pre;
scanf("%I64d%I64d",&n,&k);
for (i=0;i<n;i++)
{
scanf("%I64d%I64d",&l[i],&r[i]);
if (m.count(l[i]))
m[l[i]]++;
else
m[l[i]]=1;
if (m.count(r[i]+1))
m[r[i]+1]--;
else
m[r[i]+1]=-1;
}
fac[0]=1;
for (i=1;i<=N;i++)
fac[i]=fac[i-1]*i%moder;
for (i=0;i<=N;i++)
inv[i]=power(fac[i],moder-2);
map<long long,long long>::iterator j=m.begin();
for (;j!=m.end();j++)
{
if (j==m.begin())
count+=j->second;
else
{
if (count>=k)
ans=(ans+(j->first-pre)*fac[count]%moder*inv[count-k]%moder*inv[k]%moder)%moder;
count+=j->second;
}
pre=j->first;
}
printf("%I64d",ans);
return 0;
}