A 本关考验你求最大值功夫
直接暴力枚举 并暴力统计
,以此来更新答案,粗略观察一下,由于
如果相差过大,那求和式子一定会随着它变大而变小,所以枚举的数量级和
同级即可,复杂度
。
直接暴力枚举 ,更新答案的时候,我们可以改写一下求和式子:
其中三个求和式都可以预处理,获得答案,则可以 预处理,
枚举,复杂度
。
我们更改求和式子后,得到了形如 的式子,然后我们又知道
,于是可以将要最小化值的式子中的
都替换为
,于是得到了一个一元二次方程,只需要求出这个一元二次方程的最值点带入即可,求点复杂度
,计算最值复杂度
。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=1000005;
ll tx[M],ty[M];
int main()
{
// freopen("max.in","r",stdin);
// freopen("max.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll n,c,sumx=0,sumy=0,dltl,dltr;
cin>>n>>c;
for(int i=1;i<=n;i++) cin>>tx[i];
for(int i=1;i<=n;i++) cin>>ty[i];
for(int i=1;i<=n;i++) sumx+=tx[i];
for(int i=1;i<=n;i++) sumy+=ty[i];
ll a=(n*c+sumx-sumy)/(n*2);
dltl=(n*c+sumx-sumy)-a*n*2;
dltr=(a+1)*n*2-(n*c+sumx-sumy);
if(dltl<=dltr) cout<<a<<" "<<c-a<<"\n";
else cout<<(a+1)<<" "<<c-(a+1)<<"\n";
return 0;
}
B 本关考验你求最小值功夫
暴力建图,筛质数,跑最小生成树,任意一种最小生成树算法均可,复杂度 ,可以观察后手动排除一些边,可以骗到
。
首先考虑所有质数连通,一定是去连最近的质数,此时我们将质数连成了一条链,这是对于连通的质数集的最优方案,然后考虑如何把合数并入。
我们可以将合数挂到离自己最近的质数上去,并且两个质数之间也可以挂一个合数,那么我们可以将离两个质数差不多近的合数插在里面,其它的挂在质数上面,这样构造出的树即是最小生成树。
复杂度瓶颈就来到了筛素数,根号筛素数为 ,线性筛为
。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=10000005;
int zs[M],p[M];
void init(int n){
for(int i=2;i<=n;i++)
{
if(!p[i])
{
p[i]=i;
zs[++zs[0]]=i;
}
for(int j=1;j<=zs[0]&&i*zs[j]<=n&&p[i]>=zs[j];j++)
{
p[i*zs[j]]=zs[j];
}
}
return ;
}
int main()
{
// freopen("min.in","r",stdin);
// freopen("min.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
ll ans=1,dlt;
cin>>n;
if(n==1)
{
cout<<0<<"\n";
return 0;
}
init(n);
for(int i=1;i<zs[0];i++)
{
dlt=zs[i+1]-zs[i];
if(dlt&1) ans+=(1+dlt/2)*(dlt/2)+dlt-(dlt/2);
else ans+=dlt/2*(dlt/2-1)+dlt;
}
for(int i=zs[zs[0]];i<=n;i++)
{
ans+=i-zs[zs[0]];
}
cout<<ans<<'\n';
return 0;
}
C 本关考验你判断正误功夫
只有一种字符,我们容易得知,只要不是长度为 ,一定可以删光。
期望
由于 为
,在字符不同时随机输出 "
'' 或者 "
'',期望获得
。
区间 ,设
为下标
到
的子串能否完全删除,然后枚举断点
,得到
方程。
对于所有情况:
如果 时,还要附加上:
判断 是否为
即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=305;
bool dp[M][M];
string s,st;
void solve(){
int n;
cin>>n;
cin>>st;
s=" "+st;
memset(dp,0,sizeof(dp));
for(int len=2;len<=n;len++)
{
for(int l=1;l+len-1<=n;l++)
{
int r=l+len-1;
for(int k=l;k<r;k++)
{
dp[l][r]=max(dp[l][r],(dp[l][k]&&dp[k+1][r]));
}
if(s[l]==s[r])
{
if(len<=3) dp[l][r]=true;
else
{
dp[l][r]=max(dp[l][r],dp[l+1][r-1]);
dp[l][r]=max(dp[l][r],dp[l+2][r-1]);
dp[l][r]=max(dp[l][r],dp[l+1][r-2]);
for(int k=l+2;k<=r-2;k++)
{
dp[l][r]=max(dp[l][r],(dp[l+1][k-1]&&dp[k+1][r-1]));
}
}
}
}
}
if(dp[1][n]) cout<<"YES\n";
else cout<<"NO\n";
return ;
}
int main()
{
// freopen("judge.in","r",stdin);
// freopen("judge.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin>>T;
while(T--)
{
solve();
}
return 0;
}
/*
1
12
abcdeffdecba*/
D 本关考验你数数功夫
链
为一条链,任选两个不同的点均为花,答案为 。
菊花图
为菊花图(不讨论同为链的情况),如果不是 个点,答案为
,否则答案为
。
观察易知,一个点在连了边之后,至多有两条边在连成的环上,那如果树上存在大于 度的点,则答案必然为
。
否则,如果没有三度点,图退化为链。
如果有一个三度点,那以三度点为根,三个子链可以互相连,设其为
答案为 。
如果有大于等于 个三度点,那么所有的三度点必须都在环上,所以树上的三度点必须在一条链上,否则无解。我们取该链的两端离得最远的三度点,其链外部分的子树可以互相连,设其分别为
,答案即是
。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=1000005;
struct node{
int v,lst;
}t[M<<1];
int dp[M],du[M],upt,fa[M],tot,head[M];
ll siz[M],dep[M];
vector<ll>vt;
void add(int u,int v){
t[++tot].v=v;
t[tot].lst=head[u];
head[u]=tot;
}
void dfs1(int u,int f){
int v,flag=0;
dep[u]=dep[f]+1;
for(int i=head[u];i;i=t[i].lst)
{
v=t[i].v;
if(v==f) continue;
dfs1(v,u);
flag=1;
}
if(flag==0) vt.push_back(dep[u]-1);
return ;
}
void dfs2(int u,int f){
int v,cntt=0;
siz[u]=1;
fa[u]=f;
for(int i=head[u];i;i=t[i].lst)
{
v=t[i].v;
if(v==f) continue;
dfs2(v,u);
siz[u]+=siz[v];
if(du[u]==3&&dp[v]>=2)
{
cout<<0<<"\n";
exit(0);
}
cntt+=dp[v];
}
if(cntt==0) dp[u]=(du[u]==3);
else if(cntt==1) dp[u]=1;
else if(cntt==2) upt=u;
else
{
cout<<0<<"\n";
exit(0);
}
return ;
}
int dfs_vt(int u,int f){
int v,flag=0;
for(int i=head[u];i;i=t[i].lst)
{
v=t[i].v;
if(v==f||dp[v]==0) continue;
return dfs_vt(v,u);
}
return u;
}
int dfs_upt(int u,int f){
int v,flag=0;
if(du[u]==3) return u;
for(int i=head[u];i;i=t[i].lst)
{
v=t[i].v;
if(v==f||dp[v]==0) continue;
return dfs_upt(v,u);
}
return 0;
}
void solve0(int n){
cout<<1ll*n*(n-1)/2<<"\n";
return ;
}
void solve1(int x){
dfs1(x,0);
cout<<(vt[0]*vt[1]+vt[0]*vt[2]+vt[1]*vt[2])<<"\n";
return ;
}
void solve2(int n){
upt=-1;
dfs2(1,0);
ll lsum,rsum;
int dpt;
if(upt!=-1)
{
for(int i=head[upt];i;i=t[i].lst)
{
int v=t[i].v;
if(dp[v]==1) vt.push_back(v);
}
vt[0]=dfs_vt(vt[0],upt);
vt[1]=dfs_vt(vt[1],upt);
cout<<(siz[vt[0]]-1)*(siz[vt[1]]-1)<<"\n";
}
else
{
upt=dfs_upt(1,0);
dpt=dfs_vt(upt,fa[upt]);
lsum=siz[dpt]-1;
for(int i=head[upt];i;i=t[i].lst)
{
int v=t[i].v;
if(v==fa[upt]||dp[v]==0) continue;
rsum=n-1-siz[v];
}
// cout<<upt<<" "<<rsum<<"\n";
cout<<lsum*rsum<<"\n";
}
return ;
}
void solve(){
// freopen("flower.in","r",stdin);
// freopen("flower.out","w",stdout);
int n,u;
cin>>n;
for(int i=1;i<n;i++)
{
cin>>u;
add(i+1,u);
add(u,i+1);
du[i+1]++;
du[u]++;
}
int cnt=0,id;
for(int i=1;i<=n;i++)
{
if(du[i]>3)//有超过三度的点
{
cout<<0<<"\n";
return ;
}
if(du[i]==3) cnt++,id=i;
}
if(cnt==0) solve0(n);//一条链
else if(cnt==1) solve1(id);//一个三度点
else solve2(n);//二个或二个以上三度点
return ;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T=1;
// cin>>T;
while(T--)
{
solve();
}
return 0;
}
/*
1
12
abcdeffdecba*/

京公网安备 11010502036488号