A. ConneR and the A.R.C. Markland-N
map+暴力枚举即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)] //m是矩阵的列数
//pop_back()
const int seed=131;
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
map<int,int>mp;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--)
{
int n,s,k,x;
cin>>n>>s>>k;
mp.clear();
for(int i=1;i<=k;i++)
cin>>x,mp[x]=1;
int mi=111111;
for(int i=s;i<=n;i++)if(mp.find(i)==mp.end())
{
mi=min(mi,i-s);
break;
}
for(int i=s;i>=1;i--)
if(mp.find(i)==mp.end())
{
mi=min(s-i,mi);
break;
}
cout<<mi<<endl;
}
return 0;
}
B:最优解肯定是一个一个的减少。
因为 2/n < 1/n+1/(n-1)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)] //m是矩阵的列数
//pop_back()
const int seed=131;
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
int main()
{
int n;
cin>>n;
double ans=0;
for(double i=1.0;i<=n;i+=1)
{
ans+=1/i;
}
printf("%.10f\n",ans);
return 0;
}
C:
由于只有两行,每次火山产生时只会影响另一行相近的三格。
记录产生的障碍数,等于0则可以通过
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)] //m是矩阵的列数
//pop_back()
const int seed=131;
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
int vs[3][M];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,q;
cin>>n>>q;
ll nm=0;
while(q--)
{
int r,c;
cin>>r>>c;
r--;
vs[r][c]^=1;
if(vs[r][c])//产生岩浆
{
if(vs[r^1][c-1])nm++;
if(vs[r^1][c])nm++;
if(vs[r^1][c+1])nm++;
}
else
{
if(vs[r^1][c-1])nm--;
if(vs[r^1][c])nm--;
if(vs[r^1][c+1])nm--;
}
if(nm)cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
return 0;
}
D:
一看到倍数增长,很自然想到点数不会太多。
而且每次倍数增长,最优解肯定是收取连续的数据点。否则把中间的收取肯定更优
枚举最终收集的连续的点。
然后从起点到端点再收集完这条链上的点一定是最优走法,因为三角形两边之和大于第三边。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 LL;
//typedef unsigned long long ull;
//#define F first
//#define S second
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
const ld PI=acos(-1);
const ld eps=1e-9;
//unordered_map<int,int>mp;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
//#define a(i,j) a[(i)*(m+2)+(j)] //m是矩阵的列数
//pop_back()
const int seed=131;
const int M = 1e5+7;
/*
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int z){ee[++cnt].nxt=head[x],ee[cnt].to=y,ee[cnt].val=z,head[x]=cnt;}
*/
struct node
{
ll x,y;
}P[M];
ll dis(node a,node b)
{
ll x,y;
if(a.x>b.x)x=a.x-b.x;else x=b.x-a.x;
if(a.y>b.y)y=a.y-b.y;else y=b.y-a.y;
return x+y;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
ll ax,ay,bx,by,sx,sy,t;
cin>>P[0].x>>P[0].y>>ax>>ay>>bx>>by;
cin>>sx>>sy>>t;
int sz=0;
while(1)
{
if((1LL*3e16-bx)/ax<P[sz].x||(1LL*3e16-by)/ay<P[sz].y)break;
P[++sz].x=ax*P[sz-1].x+bx;
P[sz].y=ay*P[sz-1].y+by;
// cout<<sz<<" "<<P[sz].x<<" "<<P[sz].y<<" "<<endl;
}
// cout<<sz<<endl;
int ma=0;
for(int i=0;i<=sz;i++)
for(int j=i;j<=sz;j++)
{
ll tp=0;
for(int k=i;k<j;k++)//i ->j 连续的点经过
{
tp+=dis(P[k],P[k+1]);
}
node s=node{sx,sy};
tp+=min(dis(s,P[i]),dis(s,P[j]));
// cout<<i<<" "<<j<<" "<<tp<<endl;
if(tp<=t)ma=max(ma,j-i+1);
}
cout<<ma<<endl;
return 0;
}
/*
1 1 2 2 0 0
1 1 1
*/
E:
mex(u,v) 点u--点v的路径上所有边权,没有出现的最小自然数。
这种非常奇怪的条件非常不好维护,我们可以从贡献着想。
对于边权0一条边u-v,它产生的贡献即sizu*sizv,左右子树乘积。
而对于[0,1],1肯定要放在0旁边,不然拉长后siz左右会变小,不优。
此时额外产生的贡献是sizi*sizj。因为之前0已经算过一遍了。
同理拓展到[0,2].肯定放在[0,1]的旁边形成一条链。额外贡献同理。
我们发现:最终产生贡献的边权[0.k],一定在一条链上,除了这条链上的其他边不会产生贡献,因为没有意义。
假设一条链i,j是最终的链,它可以由长链 i,fa[i][j] 或者长链 fa[j][i],j 转移过来。
也就是说,如果这不是一棵树,而是一个数组,让我们填0--k的数,求S的最大值。
我们可以直接dp[i][j]表示 [i,j] 区间内填 [0,j-i] 数,产生的最大贡献
转移:dp[i][j]=max(dp[i][j-1],dp[i+1][j])+i*(n-j).
最后输出dp[i][j]即可。
然后转化到树上问题,我们直接枚举i,j。然后暴力转移即可。
这看似是个n^4的复杂度,但其实每个dp[i][j]加上记忆话后只会算一次。所以复杂度是n^2
最后预处理出:
fa[i][j]:以i为根j的父亲节点。
siz][j]:以i为根j的子树大小。
方便计算。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int M =3010;
vector<int>G[M];
int f[M][M];//以i为根时 j的父亲。
ll siz[M][M];//以i为根时,j的子树大小
ll dp[M][M];//以i,j为最终算贡献的链时,最大贡献是多少
//最终最大的贡献一定是一条链,链上边权为[0,k]。
void dfs(int rt,int u,int fa)
{
//cout<<u<<" "<<fa<<endl;
siz[rt][u]=1;
for(auto v:G[u])
{
if(v==fa)continue;
// cout<<u<<" "<<v<<" "<<fa<<endl;
f[rt][v]=u;
dfs(rt,v,u);
siz[rt][u]+=siz[rt][v];
}
}
ll ans;
ll gao(int i,int j)
{
// cout<<i<<" "<<j<<endl;
if(i==j)return 0;
if(dp[i][j]!=-1)return dp[i][j];
return dp[i][j]=siz[i][j]*siz[j][i]+max(gao(f[j][i],j),gao(i,f[i][j]));
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,u,v;cin>>n;
for(int i=1;i<n;i++)cin>>u>>v,G[u].pb(v),G[v].pb(u);
for(int i=1;i<=n;i++)dfs(i,i,-1);
memset(dp,-1,sizeof(dp));
// cout<<"ok"<<endl;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
gao(i,j),ans=max(ans,dp[i][j]);
cout<<ans<<endl;
return 0;
}