Codeforces Round 975 (Div. 2) A-E
人生中第一次正常\(div2\)爆写5题。cf给我正反馈最大的一次
A直接找到最大的数字的位置,然后判断一下这个数字的位置下标的奇偶性就好了。然后如果有多个最大的就取奇数位置的。这样可以算出来一定是最优解
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
char c=getchar();int a=0,b=1;
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
int n,a[101],f[101][101];
int main()
{
int T=read();
while(T--)
{
n=read();
int Max=0,Maxid;
for(int i=1;i<=n;i++)
{
a[i]=read();
if(Max<=a[i])
{
if(Max==a[i])
{
Maxid=max(Maxid,i%2);
}
else Maxid=i%2;
Max=a[i];
}
}
// cout<<Maxid<<endl;
if(n%2==0)
{
cout<<Max+n/2<<endl;
}
else
{
cout<<Max+n/2+(Maxid)<<endl;
}
}
return 0;
}
B画个图,能看出来每个点的被覆盖次数就是左边的点数$\times \(右边点数,如果这个位置上本身就有点,就是\)(左边点数+1) \times (右边点数+1)-1\(。然后可以直接把这个放到一个下表为\)k\(的map中,询问就\)O(log(n))\(查询,总体\)(q\log n)$
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
char c=getchar();ll a=0,b=1;
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll n,q,x[100001];
ll k[100001];
map<ll,ll> ma;
int main()
{
ll T=read();
while(T--)
{
n=read();q=read();
for(ll i=1;i<=n;i++)
{
x[i]=read();
}
sort(x+1,x+1+n);
ma.clear();
for(ll i=1;i<n;i++)
{
ll sum=x[i+1]-x[i]-1;
ma[i*(n-i)]+=sum;
ma[(i+1)*(n-i)-1]++;
}
ma[n-1]++;
for(ll i=1;i<=q;i++)
{
k[i]=read();
}
for(ll i=1;i<=q;i++)
{
cout<<ma[k[i]]<<' ';
}
cout<<endl;
}
return 0;
}
C人类智慧...卡我好久,和很久之前做的一个题目很像。这也导致我想歪了。和整除分块有一点点类似,但是还是不一样,把画个图把不等式写出来就结束了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read() {
char c=getchar();ll a=0,b=1;
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
ll n,k,a[200001];
int main()
{
ll T=read();
while(T--)
{
n=read(),k=read();
ll Max=0;ll sum=0;
for(ll i=1;i<=n;i++)
{
a[i]=read();
Max=max(Max,a[i]);
sum+=a[i];
}
ll rsum=sum+k;
ll ans=0;//×î½Ó½üµÄ¿¨×éÊý
for(ll i=n;i>=1;i--)//ºñ¶È
{
if((rsum/i)>=((sum+i-1)/i)&&(rsum/i)>=Max)
{
ans=i;
break;
}
// ll Ned=i*now;
// if(Ned<=rsum)
// {
// }
// if((i-1)*now<sum)//ÕâÖÖʱºò²ÅÐèÒªÔö¼Ó¿¨×éÊý
// {
// ll back=
// }
}
cout<<ans<<endl;
}
return 0;
}
/*
1
5 4
2 6 1 2 4
*/
D比C简单很多,我开始看题到写完就花了20分钟
先考虑找到一个解,发现直接给所有城市按照ddl排序,然后从小的开始向大的覆盖,如果这样的操作是无解的,可以证明一定无解。
然后根据这个,可以推导出一个很重要的贪心,就是最后有解的城市一定是一个完整的答案区间。也就是能够作为起点的城市一定是一个连续的区间。
证明的话,根据我们判断是否有解的贪心可以感性理解,正确性还是挺明显的。
然后根据这个,先以ddl最小的点开始作为起点,向左右二分这个答案区间的边界,就能够找到答案。我写的是倍增,二分一样的。总复杂度\(O(n\log n)\)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int a=0,b=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
return a*b;
}
int n,b[200001];
struct city
{
int id,ddl;
}a[200001];
bool cmp(city a,city b)
{
return a.ddl<b.ddl;
}
int main()
{
int T=read();
while(T--)
{
n=read();
for(int i=1;i<=n;i++)
{
b[i]=a[i].ddl=read();
a[i].id=i;
}
sort(a+1,a+1+n,cmp);
int st=a[1].id;
int now=1,l,r;l=r=a[1].id;
for(int i=2;i<=n;i++)
{
if(a[i].id<l)
{
now+=l-a[i].id;
if(now>a[i].ddl)break;
l=a[i].id;
}
if(a[i].id>r)
{
now+=a[i].id-r;
if(now>a[i].ddl)break;
r=a[i].id;
}
}
if(!(l==1&&r==n))
{
cout<<0<<endl;
continue;
}
int Maxl=st,Maxr=st;
int nowm=19;
while(nowm>=0)
{
if(Maxl-(1<<nowm)<=0)
{
nowm--;
continue;
}
l=r=a[1].id;
now=1;l=r=Maxl-(1<<nowm);
for(int i=1;i<=n;i++)
{
if(a[i].id<l)
{
now+=l-a[i].id;
if(now>a[i].ddl)break;
l=a[i].id;
}
if(a[i].id>r)
{
now+=a[i].id-r;
if(now>a[i].ddl)break;
r=a[i].id;
}
}
if((l==1&&r==n))Maxl-=(1<<nowm);
nowm--;
}
nowm=19;
while(nowm>=0)
{
if(Maxr+(1<<nowm)>n)
{
nowm--;
continue;
}
l=r=a[1].id;
now=1;l=r=Maxr+(1<<nowm);
for(int i=1;i<=n;i++)
{
if(a[i].id<l)
{
now+=l-a[i].id;
if(now>a[i].ddl)break;
l=a[i].id;
}
if(a[i].id>r)
{
now+=a[i].id-r;
if(now>a[i].ddl)break;
r=a[i].id;
}
}
if((l==1&&r==n))Maxr+=(1<<nowm);
nowm--;
}
cout<<Maxr-Maxl+1<<endl;
}
return 0;
}
E题,我的做法很暴力,就是把所有点按照深度排序,然后每次就把相同深度的点和根节电拿出来建立虚树,然后计算这个虚数的边数,用\(n-1\)减去这个数字就是这个深度的答案。计算边数可以用lca,具体参考"异象石"这题。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read(){
int a=0,b=1;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
return a*b;
}
int n,head[1000001],tot,Size[500001],dep[500001][22],f[500001][22],dfn[500001],cnt;
struct edge
{
int next,to;
}e[1000001];
inline void add(int i,int j)
{
e[++tot].next=head[i];
e[tot].to=j;
head[i]=tot;
}
void pre(int x,int fa)
{
Size[x]=1;f[x][0]=fa;dep[x][0]=dep[fa][0]+1;dfn[x]=++cnt;
for(int i=head[x];i!=0;i=e[i].next)
{
int u=e[i].to;
if(u==fa)continue;
pre(u,x);
Size[x]+=Size[u];
}
}
int Lca(int x,int y)
{
if(dep[x][0]<dep[y][0])swap(x,y);
int now=21;
while(now>=0)
{
if(dep[x][now]>dep[y][0])x=f[x][now];
now--;
}
if(x==y)return x;
now=21;
while(now>=0)
{
if(f[x][now]!=f[y][now])x=f[x][now],y=f[y][now];
now--;
}
return f[x][0];
}
inline Count(int x,int y)
{
int lca=Lca(x,y);
return dep[x][0]+dep[y][0]-dep[lca][0]*2;
}
vector<int> fdp[500001];
bool cmp(int a,int b)
{
return dfn[a]<dfn[b];
}
int main()
{
int T=read();
while(T--)
{
for(int i=1;i<=tot;i++)head[i]=0;
tot=0;
n=read();
for(int i=1;i<n;i++)
{
int x=read(),y=read();
add(x,y);add(y,x);
}
cnt=0;
dep[0][0]=-1;
pre(1,0);
for(int j=0;j<21;j++)
{
for(int i=1;i<=n;i++)
{
f[i][j+1]=f[f[i][j]][j];
dep[i][j+1]=dep[f[i][j]][j];
}
}
for(int i=0;i<=n;i++)fdp[i].clear();
for(int i=0;i<=n;i++)
{
fdp[dep[i][0]].push_back(i);
}
int ans=0;
for(int i=0;i<=n;i++)
{
if(fdp[i].size()==0)continue;
sort(fdp[i].begin(),fdp[i].end(),cmp);
int sum=0,Alllca=Lca(fdp[i][0],fdp[i][fdp[i].size()-1]);
for(int j=0;j<fdp[i].size()-1;j++)
{
sum+=Count(fdp[i][j],fdp[i][j+1]);
Alllca=Lca(Alllca,fdp[i][j]);
}
sum+=Count(fdp[i][0],fdp[i][fdp[i].size()-1]);
sum/=2;
sum+=dep[Alllca][0];
// cout<<i<<' '<<sum<<' '<<Alllca<<' '<<dep[Alllca][0]<<endl;
ans=max(ans,sum);
}
cout<<(n-1)-ans<<endl;
}
return 0;
}