A
最小的四个近似素数
为
6
,
10
,
14
,
15
6,10,14,15
6,10,14,15,容易发现,当
n
≤
30
n\leq 30
n≤30 时,是一定无解的,因为最小的三个近似素数
加起来就有
30
30
30。
否则的话,我们一定可以用 6 , 10 , 14 , n − 30 6,10,14,n-30 6,10,14,n−30 或 6 , 10 , 15 , n − 31 6,10,15,n-31 6,10,15,n−31 来表示出 n n n,因为当第一种方式表示不出来时,一定满足 n − 30 n-30 n−30 等于 6 , 10 , 14 6,10,14 6,10,14 中的一个,那么 n − 31 n-31 n−31 就不可能等于 6 , 10 , 15 6,10,15 6,10,15 中的任何一个。
代码如下:
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
namespace my
{
//-----------------------------------------------------------------------------
inline char cn()
{
static char buf[1000010],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
#define cn getchar
template<class TY>void read(TY &x)
{
x=0;int f1=1;char ch=cn();
while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
}
char Output[1000100],Zk[100];int op_top=0,Zk_top;
void fcheck(int Type=0){if(Type||op_top>=1000000)fwrite(Output,1,op_top,stdout),op_top=0;}
template<class TY>inline void write(TY x)
{
if(x==0){Output[op_top++]='0';fcheck();return;}
Zk_top=0;while(x)Zk[++Zk_top]=x%10+'0',x/=10;
while(Zk_top)Output[op_top++]=Zk[Zk_top--];fcheck();
}
#define K_G Output[op_top++]=' '
#define H_C Output[op_top++]='\n'
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define INV(x) ksm(x,mod-2)
#define inf 999999999
#define mod 998244353
template<class TY>void add(TY &x,TY y){x=(x+y>=mod?x+y-mod:x+y);}
template<class TY>void dec(TY &x,TY y){x=(x-y<0?x-y+mod:x-y);}
template<class TY>TY add(TY x){return x>=mod?x-mod:x;}
template<class TY>TY dec(TY x){return x<0?x+mod:0;}
//
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
int *fac,*inv_fac,*inv;
void work_math(const int N)
{
fac=new int[N+5];inv_fac=new int[N+5];inv=new int[N+5];
inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
fac[0]=inv_fac[0]=1;for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv_fac[N]=INV(fac[N]);
for(int i=N-1;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
}
int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
//
template<class TY>TY gcd(TY x,TY y){return !y?x:gcd(y,x%y);}
template<class TY>TY exgcd(TY a,TY b,TY &x,TY &y){
if(!b)return x=1,y=0,a;
TY re=exgcd(b,a%b,y,x);
return y-=a/b*x,re;
}
//
template<class TY>void discretization(TY *arr,int St,int Ed){
vector<TY>Arr;Arr.clear();
for(int i=St;i<=Ed;i++)Arr.push_back(arr[i]);
sort(Arr.begin(),Arr.end());
for(int i=St;i<=Ed;i++)arr[i]=lower_bound(Arr.begin(),Arr.end(),arr[i])-Arr.begin()+1;
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
int T,n;
void main()
{
read(T);while(T--)
{
read(n);//6 10 14
if(n>30){
printf("YES\n");
if(n-30!=6&&n-30!=10&&n-30!=14)printf("6 10 14 %d\n",n-30);
else printf("6 10 15 %d\n",n-31);
}else printf("NO\n");
}
fcheck(1);return;
}
}
int main(){my::main();return 0;}
B
仔细思考,可以发现答案一定是若干个 9 9 9 加若干个 8 8 8,前面的 9 9 9 是为了让 r r r 最大, 8 8 8 是为了在 k k k 最小的前提下提供尽可能多的二进制位,这样删掉后 n n n 位后可以让 r r r 的位数最多。
代码如下:
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
namespace my
{
//-----------------------------------------------------------------------------
inline char cn()
{
static char buf[1000010],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
#define cn getchar
template<class TY>void read(TY &x)
{
x=0;int f1=1;char ch=cn();
while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
}
char Output[1000100],Zk[100];int op_top=0,Zk_top;
void fcheck(int Type=0){if(Type||op_top>=1000000)fwrite(Output,1,op_top,stdout),op_top=0;}
template<class TY>inline void write(TY x)
{
if(x==0){Output[op_top++]='0';fcheck();return;}
Zk_top=0;while(x)Zk[++Zk_top]=x%10+'0',x/=10;
while(Zk_top)Output[op_top++]=Zk[Zk_top--];fcheck();
}
#define K_G Output[op_top++]=' '
#define H_C Output[op_top++]='\n'
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define INV(x) ksm(x,mod-2)
#define inf 999999999
#define mod 998244353
template<class TY>void add(TY &x,TY y){x=(x+y>=mod?x+y-mod:x+y);}
template<class TY>void dec(TY &x,TY y){x=(x-y<0?x-y+mod:x-y);}
template<class TY>TY add(TY x){return x>=mod?x-mod:x;}
template<class TY>TY dec(TY x){return x<0?x+mod:0;}
//
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
int *fac,*inv_fac,*inv;
void work_math(const int N)
{
fac=new int[N+5];inv_fac=new int[N+5];inv=new int[N+5];
inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
fac[0]=inv_fac[0]=1;for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv_fac[N]=INV(fac[N]);
for(int i=N-1;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
}
int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
//
template<class TY>TY gcd(TY x,TY y){return !y?x:gcd(y,x%y);}
template<class TY>TY exgcd(TY a,TY b,TY &x,TY &y){
if(!b)return x=1,y=0,a;
TY re=exgcd(b,a%b,y,x);
return y-=a/b*x,re;
}
//
template<class TY>void discretization(TY *arr,int St,int Ed){
vector<TY>Arr;Arr.clear();
for(int i=St;i<=Ed;i++)Arr.push_back(arr[i]);
sort(Arr.begin(),Arr.end());
for(int i=St;i<=Ed;i++)arr[i]=lower_bound(Arr.begin(),Arr.end(),arr[i])-Arr.begin()+1;
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
int T,n;
void main()
{
read(T);while(T--)
{
read(n);
int a=n/4,b=(n%4>0);
for(int i=1;i<=n-a-b;i++)write(9);
for(int i=1;i<=a+b;i++)write(8);
}
fcheck(1);return;
}
}
int main(){my::main();return 0;}
C
人从树根往每个点走,在路上可能心情由好变不好,转化一下就是:人从每个点往根走,在路上可能心情由不好变好。
假设 x x x 子树内的所有人心情都是好的,那么可以得到该点的心情指数的上限,而将所有儿子的 h h h 加起来,再加上 − p [ x ] -p[x] −p[x],则可以得到心情指数的下限,我们需要判断 h [ x ] h[x] h[x] 是否在这个上下限内。
如果一个人的心情由坏变好,那么心情指数会 + 2 +2 +2,所以需要判断 h [ x ] h[x] h[x] 到上下限的距离是否为偶数。
但凡有一个人不满足上面一个要求,那么答案就是NO了,代码如下:
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
namespace my
{
//-----------------------------------------------------------------------------
inline char cn()
{
static char buf[1000010],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
#define cn getchar
template<class TY>void read(TY &x)
{
x=0;int f1=1;char ch=cn();
while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
}
char Output[1000100],Zk[100];int op_top=0,Zk_top;
void fcheck(int Type=0){if(Type||op_top>=1000000)fwrite(Output,1,op_top,stdout),op_top=0;}
template<class TY>inline void write(TY x)
{
if(x==0){Output[op_top++]='0';fcheck();return;}
Zk_top=0;while(x)Zk[++Zk_top]=x%10+'0',x/=10;
while(Zk_top)Output[op_top++]=Zk[Zk_top--];fcheck();
}
#define K_G Output[op_top++]=' '
#define H_C Output[op_top++]='\n'
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define INV(x) ksm(x,mod-2)
#define inf 999999999
#define mod 998244353
template<class TY>void add(TY &x,TY y){x=(x+y>=mod?x+y-mod:x+y);}
template<class TY>void dec(TY &x,TY y){x=(x-y<0?x-y+mod:x-y);}
template<class TY>TY add(TY x){return x>=mod?x-mod:x;}
template<class TY>TY dec(TY x){return x<0?x+mod:0;}
//
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
int *fac,*inv_fac,*inv;
void work_math(const int N)
{
fac=new int[N+5];inv_fac=new int[N+5];inv=new int[N+5];
inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
fac[0]=inv_fac[0]=1;for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv_fac[N]=INV(fac[N]);
for(int i=N-1;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
}
int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
//
template<class TY>TY gcd(TY x,TY y){return !y?x:gcd(y,x%y);}
template<class TY>TY exgcd(TY a,TY b,TY &x,TY &y){
if(!b)return x=1,y=0,a;
TY re=exgcd(b,a%b,y,x);
return y-=a/b*x,re;
}
//
template<class TY>void discretization(TY *arr,int St,int Ed){
vector<TY>Arr;Arr.clear();
for(int i=St;i<=Ed;i++)Arr.push_back(arr[i]);
sort(Arr.begin(),Arr.end());
for(int i=St;i<=Ed;i++)arr[i]=lower_bound(Arr.begin(),Arr.end(),arr[i])-Arr.begin()+1;
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
#define maxn 100010
int T,n,m;
struct edge{int y,next;}e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
ll a[maxn],h[maxn],size[maxn];
bool ans;
void dfs(int x,int fa){
ll tot=-a[x];
for(int i=first[x];i;i=e[i].next){
int y=e[i].y;if(y==fa)continue;
dfs(y,x);tot+=h[y];a[x]+=a[y];
}
bool v1=(tot%2!=0),v2=(a[x]%2!=0);
if(v1!=v2)ans=false;//这一句可能是多余的,总之写上比较保险
if(h[x]<tot||h[x]>a[x])ans=false;
if((h[x]-tot)%2)ans=false;
}
void main()
{
read(T);while(T--)
{
read(n);read(m);
for(int i=1;i<=n;i++)read(a[i]);
for(int i=1;i<=n;i++)read(h[i]);
memset(first,0,(n+1)<<2);len=0;
for(int i=1,x,y;i<n;i++)read(x),read(y),
buildroad(x,y),buildroad(y,x);
ans=true;dfs(1,0);
if(ans)printf("YES\n");
else printf("NO\n");
}
fcheck(1);return;
}
}
int main(){my::main();return 0;}
T4
可以发现所有位置构成了一个森林的结构,那么我们只需要确定每对父子间的操作顺序,就可以得到总的操作顺序了。
要使得答案尽可能大,那么可以考虑贪心,设 f [ x ] f[x] f[x] 表示 x x x 位置能达到的最大值,那么它的父亲在考虑 x x x 时,假如 f [ x ] f[x] f[x] 大于 0 0 0,那么肯定先操作 x x x,再操作 x x x 的父亲。
将这些操作顺序造成图, x → y x\to y x→y 这条边表示 x x x 的操作顺序在 y y y 之前,然后求一下这张图的拓扑序即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
namespace my
{
//-----------------------------------------------------------------------------
inline char cn()
{
static char buf[1000010],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
#define cn getchar
template<class TY>void read(TY &x)
{
x=0;int f1=1;char ch=cn();
while(ch<'0'||ch>'9'){if(ch=='-')f1=-1;ch=cn();}
while(ch>='0'&&ch<='9')x=x*10+(ch-'0'),ch=cn(); x*=f1;
}
char Output[1000100],Zk[100];int op_top=0,Zk_top;
void fcheck(int Type=0){if(Type||op_top>=1000000)fwrite(Output,1,op_top,stdout),op_top=0;}
template<class TY>inline void write(TY x)
{
if(x==0){Output[op_top++]='0';fcheck();return;}
if(x<0)Output[op_top++]='-',x=-x;
Zk_top=0;while(x)Zk[++Zk_top]=x%10+'0',x/=10;
while(Zk_top)Output[op_top++]=Zk[Zk_top--];fcheck();
}
#define K_G Output[op_top++]=' '
#define H_C Output[op_top++]='\n'
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define INV(x) ksm(x,mod-2)
#define inf 999999999
#define mod 998244353
template<class TY>void add(TY &x,TY y){x=(x+y>=mod?x+y-mod:x+y);}
template<class TY>void dec(TY &x,TY y){x=(x-y<0?x-y+mod:x-y);}
template<class TY>TY add(TY x){return x>=mod?x-mod:x;}
template<class TY>TY dec(TY x){return x<0?x+mod:0;}
//
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
int *fac,*inv_fac,*inv;
void work_math(const int N)
{
fac=new int[N+5];inv_fac=new int[N+5];inv=new int[N+5];
inv[1]=1;for(int i=2;i<=N;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
fac[0]=inv_fac[0]=1;for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv_fac[N]=INV(fac[N]);
for(int i=N-1;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
}
int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
//
template<class TY>TY gcd(TY x,TY y){return !y?x:gcd(y,x%y);}
template<class TY>TY exgcd(TY a,TY b,TY &x,TY &y){
if(!b)return x=1,y=0,a;
TY re=exgcd(b,a%b,y,x);
return y-=a/b*x,re;
}
//
template<class TY>void discretization(TY *arr,int St,int Ed){
vector<TY>Arr;Arr.clear();
for(int i=St;i<=Ed;i++)Arr.push_back(arr[i]);
sort(Arr.begin(),Arr.end());
for(int i=St;i<=Ed;i++)arr[i]=lower_bound(Arr.begin(),Arr.end(),arr[i])-Arr.begin()+1;
}
//-----------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------
#define maxn 200010
int n,du[maxn];
ll val[maxn],ans=0;
struct edge{int y,next;}e[maxn<<1];
int first[maxn],len=0;
void buildroad(int x,int y){e[++len]=(edge){y,first[x]};first[x]=len;}
vector<int>st,to[maxn];
void dfs(int x){
for(int i=first[x];i;i=e[i].next){
int y=e[i].y;dfs(y);
if(val[y]>0)val[x]+=val[y],to[y].push_back(x),du[x]++;
else to[x].push_back(y),du[y]++;
}
ans+=val[x];
}
int zhan[maxn],t=0;
void main()
{
read(n);st.clear();
for(int i=1;i<=n;i++)read(val[i]);
for(int i=1,fa;i<=n;i++){
read(fa);to[i].clear();
if(fa==-1)st.push_back(i);
else buildroad(fa,i);
}
for(int i=0;i<st.size();i++)dfs(st[i]);
write(ans);H_C;
for(int i=1;i<=n;i++)if(!du[i])zhan[++t]=i;
while(t){
int x=zhan[t--];
write(x);K_G;
for(int i=0;i<to[x].size();i++){
du[to[x][i]]--;
if(!du[to[x][i]])zhan[++t]=to[x][i];
}
}
fcheck(1);return;
}
}
int main(){my::main();return 0;}
E
做法是膜的洛谷里的题解qwq。
先将整个平面沿着 y = x y=x y=x 这条直线翻转,这样就避免了斜率不存在的情况。
一开始自己的想法是直接三分斜率,因为令 f ( k ) f(k) f(k) 表示斜率为 k k k 时的答案,那么 f ( x ) f(x) f(x) 比较显然是个单谷函数,但是三分到不合法斜率时难以处理,有可能可行解夹在两个不合法斜率之间。
洛谷题解做法是,先枚举两两线段,它们之间存在一个不合法斜率区间,斜率如果取这个区间那么这两条线段会相交,将所有区间取并就是斜率的不合法取值范围。
有一个小结论,所有不合法区间取并之后,会得到若干个斜率区间,答案最优时,斜率一定取某个区间的端点。
证明很简单,因为当斜率变化时答案具有凸性,所以如果一个斜率 k k k 是可行解并且 k k k 不在某个区间的端点上,那么将 k k k 往 f ( k ) f(k) f(k) 的谷的位置移动一定会使得答案更优,一直移动下去就撞到某个区间的端点上了。
所以只需要把所有区间的端点拿出来三分即可。
代码如下:
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define maxn 2010
#define eps 1e-10
int n;
struct segment{int l,r,x;}a[maxn];
struct par{double k;int id;};
vector<par>s;
vector<double>k;
bool cmp(par x,par y){return x.k==y.k?(x.id>y.id):x.k<y.k;}
double calc(double k_){
double mi=1e18,ma=-1e18;
for(int i=1;i<=n;i++)mi=min(mi,1.0*a[i].l-k_*a[i].x),ma=max(ma,1.0*a[i].r-k_*a[i].x);
return ma-mi;
}
int main()
{
scanf("%d",&n);s.clear();k.clear();
for(int i=1;i<=n;i++)scanf("%d %d %d",&a[i].l,&a[i].r,&a[i].x);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++)if(a[i].x!=a[j].x){
double k1=1.0*(a[i].r-a[j].l)/(a[i].x-a[j].x);
double k2=1.0*(a[i].l-a[j].r)/(a[i].x-a[j].x);
if(k1>k2)swap(k1,k2);
s.push_back((par){k1+eps,-1});s.push_back((par){k2-eps,1});
}
}
sort(s.begin(),s.end(),cmp);
for(int i=0,tot=0;i<s.size();i++){
if(s[i].id==-1&&tot==0)k.push_back(s[i].k);
if(s[i].id==1&&tot==-1)k.push_back(s[i].k);
tot+=s[i].id;
}
if(!k.size())return printf("%.8lf",calc(0)),0;
int l=0,r=k.size()-1,mid1,mid2;
while(r-l>2){
mid1=l+(r-l+1)/3;
mid2=mid1+(r-l+1)/3;
if(calc(k[mid1])-calc(k[mid2])>eps)l=mid1+1;
else r=mid2-1;
}
double ans=calc(k[l]);
for(int i=l+1;i<=r;i++)ans=min(ans,calc(k[i]));
printf("%.8lf",ans);
}