考前的模拟赛
respect_lowsmile · · 个人记录
10.22(10pts=5pts+0pts+5pts)
我严重怀疑我是唯一一个
T1
T286189 莫比乌斯反演(mobius)
第一题一开始花了不到
也想到了枚举完前
也想到了用 现在想想自己真NT
其实解决方案很简单,只需要将
#include<iostream>
#include<map>
#define int long long
using namespace std;
const int N=3005;
map<int,int> Map;
int n,ans;
int a[N];
int gcd(int a,int b)
{
if(b==0) return a;
else return gcd(b,a%b);
}
signed main()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
for(int i=1;i<=n;++i)
{
Map.clear();
for(int j=n;j>i;Map[a[j]]++,--j)
{
int Gcd=gcd(a[i],a[j]);
ans+=Map[Gcd];
}
}
printf("%lld",ans);
return 0;
}
T2
T286185 柯西收敛准则 (cauchy)
思路:二分+dp
T286186 快速树论变换(ttt)
思路:树上贪心
白给的
正解一听学长讲好像也挺简单的,在这里感谢一下 zcx 学长。
首先,我们考虑最简单的情况。
我们设填满
很明显,我们选择的顺序不同,结果是不同的,所以我们要考虑怎么选择顺序最优。
如果先处理
我们发现,花费只与
而我们的
所以,我们按照
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=1e6+5;
vector<int> son[N];
int val[N],ans[N];
int n;
int cmp(int a,int b)
{
return ans[a]-val[a]>ans[b]-val[b];
}
void dfs(int now,int fa)
{
for(int i=0;i<son[now].size();++i)
{
int v=son[now][i];
if(v==fa) continue;
dfs(v,now);
}
sort(son[now].begin(),son[now].end(),cmp);
int rest=0;
for(int i=0;i<son[now].size();++i)
{
int v=son[now][i];
if(rest-ans[v]>=0) rest-=val[v];
else
ans[now]+=ans[v]-rest,rest=ans[v]-val[v];
}
ans[now]+=max(0,val[now]-rest);
}
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;++i)
{
int x;
scanf("%d",&x);
son[x].push_back(i);
}
for(int i=1;i<=n;++i)
scanf("%d",&val[i]);
dfs(1,0);
for(int i=1;i<=n;++i)
printf("%d ",ans[i]);
return 0;
}
T4就算了吧,又是树形dp又是组合数的
10.24(150pts=100pts+20pts+15pts+15pts)
终于考过了myf一次
T1
T286369 方程(equation)
很像数学但又不是数学的题目。
这里扯一下我考试时的做法。。。
发现题目限制
题目的式子为:
发现可以把
由
所以
#include<iostream>
#define int long long
using namespace std;
int T;
signed main()
{
freopen("equation.in","r",stdin);
freopen("equation.out","w",stdout);
scanf("%lld",&T);
while(T--)
{
int ans=0;
int a,b,c,d;
scanf("%lld %lld %lld %lld",&a,&b,&c,&d);
int maxc=c*d;
for(int i=1;i<maxc;++i)
{
int fz=a*c*i,fm=c*d-b*i;
double A=(double)fz*1.0/fm*1.0;
if(A<=0) continue;
int AA=A;
if(A-AA==0) ans++;
}
printf("%lld\n",ans);
}
return 0;
}
T2
T286378 异或数列 (xor)
异或?基本没接触过,考试的时候看到就没想去写正解,写了
其实这个题只用到了异或的一个性质,那就是自反性,即
因为修改操作是在
10.25(30pts=30pts+0pts+0pts+0pts)
大寄。
10.26(0pts......)
考前模拟赛保龄还有救吗。。。
10.27(0pts......)
不说了,满脸都是泪。。。
10.31(0pts?100pts=100pts+0pts+0pts)
突然发现自己的头文件写错了 3 年了。。。
最近模拟赛怎么都这么离谱,三个题一个数学+两个
T1
T288138 A
诈骗题。
考场上直接打表找规律,发现只有
让我们看一下
最小的质数为
然后分情况讨论与
n \% 4=0
可以构造成
n \% 4=1
可以构造成
这种构造方式要求
n \% 4=2
可以构造成
这种构造方式要求
n \% 4=3
可以构造成
这种构造方式要求
也就是说,
剩下的一小部分数打个表即可。
#include<iostream>
//#include<cstdio>
#define int long long
using namespace std;
int T;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9')
{ if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9')
{ s=s*10+ch-'0'; ch=getchar();}
return s*w;
}
signed main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
T=read();
while(T--)
{
int n=read();
if(n==1||n==2||n==3||n==5||n==7||n==11) printf("0\n");
else printf("1\n");
}
return 0;
}
T2
T288157 b
怎么又是异或。。。
11.1(120pts=100pts+20pts+0pts)
11.2(CSP-S)(175pts=50pts+85pts+40pts+0pts)
今年的
第二题漏了两种情况,挂了
T1
第一题就不会。。。
50pts
首先,预处理出每一个点通过不超过
然后处理出所有点能到达的点的点权的最大值,次大值,次大值的次大值。
为什么要处理三个值呢?
因为题目要求选取
如果只维护最大值和次大值,可能会造成因为两次重复而无法取到第三个点。
#include<bits/stdc++.h>
#include<iostream>
#include<bitset>
#include<cstdio>
#define int long long
using namespace std;
const int N=2505;
const int K=105;
const int M=1e5+5;
struct node
{
int to,next;
};
node edge[M<<1];
bitset<N> Map[N][K];
int head[N],val[N],max1[N],max2[N],max3[N];
int n,m,kk,num,Ans;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9')
{ if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9')
{ s=s*10+ch-'0'; ch=getchar();}
return s*w;
}
void add(int u,int v)
{
++num;
edge[num].to=v;
edge[num].next=head[u];
head[u]=num;
}
signed main()
{
n=read(),m=read(),kk=read();
for(int i=2;i<=n;++i) val[i]=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
add(u,v),add(v,u);
Map[u][0].set(v),Map[v][0].set(u);
}
for(int k=1;k<=kk;++k)
for(int now=1;now<=n;++now)
{
Map[now][k]=Map[now][k-1];
for(int i=head[now];i;i=edge[i].next)
{
int v=edge[i].to;
Map[now][k] |= Map[v][k-1];
}
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
if(i==j) continue;
if(!Map[i][kk][j]||!Map[1][kk][j]) continue;
if(val[j]>=val[max1[i]])
max3[i]=max2[i],max2[i]=max1[i],max1[i]=j;
else if(val[j]>=val[max2[i]])
max3[i]=max2[i],max2[i]=j;
else if(val[j]>val[max3[i]])
max3[i]=j;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
if(i==j) continue;
if(!Map[i][kk][j]) continue;
int A=0,D=0;
if(j!=max1[i]) A=max1[i];
else if(j!=max2[i]) A=max2[i];
else if(j!=max3[i]) A=max3[i];
if(i!=max1[j]&&A!=max1[j]) D=max1[j];
else if(i!=max2[j]&&A!=max2[j]) D=max2[j];
else if(i!=max3[j]&&A!=max3[j]) D=max3[j];
if(A&&D) Ans=max(Ans,val[i]+val[j]+val[A]+val[D]);
}
printf("%lld",Ans);
return 0;
}
复杂度
T2
唯一会做的题目,还因为少考虑了两种情况挂了
很明显,答案只与两个区间的最大非负数,最大负数,最小非负数,最小负数有关。
建
这边建议枚举所有算法然后进行选择,不建议列举所有情况,我才不会告诉你我因为枚举情况漏了2种挂了15分。
#include<iostream>
#define lc now<<1
#define rc now<<1|1
#define int long long
using namespace std;
const int N=1e5+5;
const int INF=0x3f3f3f3f;
struct node
{
int maxz,minz,maxf,minf;
};
node tree[N<<2],Tree[N<<2];
int n,m,q;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9')
{ if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9')
{ s=s*10+ch-'0'; ch=getchar();}
return s*w;
}
void push_up(int now)
{
tree[now].maxz=max(tree[lc].maxz,tree[rc].maxz);
tree[now].maxf=max(tree[lc].maxf,tree[rc].maxf);
tree[now].minf=min(tree[lc].minf,tree[rc].minf);
tree[now].minz=min(tree[lc].minz,tree[rc].minz);
}
void build(int now,int l,int r)
{
tree[now].minz=INF,tree[now].maxf=-INF;
if(l==r)
{
int x=read();
if(x>=0) tree[now].maxz=tree[now].minz=x;
else tree[now].maxf=tree[now].minf=x;
return ;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
push_up(now);
}
int query_maxz(int now,int l,int r,int L,int R)
{
int maxz=0;
if(l>=L&&r<=R)
return tree[now].maxz;
int mid=(l+r)>>1;
if(L<=mid) maxz=max(maxz,query_maxz(lc,l,mid,L,R));
if(R>mid) maxz=max(maxz,query_maxz(rc,mid+1,r,L,R));
return maxz;
}
int query_maxf(int now,int l,int r,int L,int R)
{
int maxf=-INF;
if(l>=L&&r<=R)
return tree[now].maxf;
int mid=(l+r)>>1;
if(L<=mid) maxf=max(maxf,query_maxf(lc,l,mid,L,R));
if(R>mid) maxf=max(maxf,query_maxf(rc,mid+1,r,L,R));
return maxf;
}
int query_minz(int now,int l,int r,int L,int R)
{
int minz=INF;
if(l>=L&&r<=R)
return tree[now].minz;
int mid=(l+r)>>1;
if(L<=mid) minz=min(minz,query_minz(lc,l,mid,L,R));
if(R>mid) minz=min(minz,query_minz(rc,mid+1,r,L,R));
return minz;
}
int query_minf(int now,int l,int r,int L,int R)
{
int minf=0;
if(l>=L&&r<=R)
return tree[now].minf;
int mid=(l+r)>>1;
if(L<=mid) minf=min(minf,query_minf(lc,l,mid,L,R));
if(R>mid) minf=min(minf,query_minf(rc,mid+1,r,L,R));
return minf;
}
void Push_up(int now)
{
Tree[now].maxz=max(Tree[lc].maxz,Tree[rc].maxz);
Tree[now].maxf=max(Tree[lc].maxf,Tree[rc].maxf);
Tree[now].minf=min(Tree[lc].minf,Tree[rc].minf);
Tree[now].minz=min(Tree[lc].minz,Tree[rc].minz);
}
void Build(int now,int l,int r)
{
Tree[now].minz=INF,Tree[now].maxf=-INF;
if(l==r)
{
int x=read();
if(x>=0) Tree[now].maxz=Tree[now].minz=x;
else Tree[now].maxf=Tree[now].minf=x;
return ;
}
int mid=(l+r)>>1;
Build(lc,l,mid);
Build(rc,mid+1,r);
Push_up(now);
}
int Query_maxz(int now,int l,int r,int L,int R)
{
int maxz=0;
if(l>=L&&r<=R)
return Tree[now].maxz;
int mid=(l+r)>>1;
if(L<=mid) maxz=max(maxz,Query_maxz(lc,l,mid,L,R));
if(R>mid) maxz=max(maxz,Query_maxz(rc,mid+1,r,L,R));
return maxz;
}
int Query_maxf(int now,int l,int r,int L,int R)
{
int maxf=-INF;
if(l>=L&&r<=R)
return Tree[now].maxf;
int mid=(l+r)>>1;
if(L<=mid) maxf=max(maxf,Query_maxf(lc,l,mid,L,R));
if(R>mid) maxf=max(maxf,Query_maxf(rc,mid+1,r,L,R));
return maxf;
}
int Query_minz(int now,int l,int r,int L,int R)
{
int minz=INF;
if(l>=L&&r<=R)
return Tree[now].minz;
int mid=(l+r)>>1;
if(L<=mid) minz=min(minz,Query_minz(lc,l,mid,L,R));
if(R>mid) minz=min(minz,Query_minz(rc,mid+1,r,L,R));
return minz;
}
int Query_minf(int now,int l,int r,int L,int R)
{
int minf=0;
if(l>=L&&r<=R)
return Tree[now].minf;
int mid=(l+r)>>1;
if(L<=mid) minf=min(minf,Query_minf(lc,l,mid,L,R));
if(R>mid) minf=min(minf,Query_minf(rc,mid+1,r,L,R));
return minf;
}
signed main()
{
//freopen("game.in","r",stdin);
//freopen("game.out","w",stdout);
n=read(),m=read(),q=read();
build(1,1,n);
Build(1,1,m);
while(q--)
{
int l1=read(),r1=read(),l2=read(),r2=read();
int maxz=query_maxz(1,1,n,l1,r1),maxf=query_maxf(1,1,n,l1,r1),minf=query_minf(1,1,n,l1,r1),minz=query_minz(1,1,n,l1,r1);
int Maxz=Query_maxz(1,1,m,l2,r2),Maxf=Query_maxf(1,1,m,l2,r2),Minf=Query_minf(1,1,m,l2,r2),Minz=Query_minz(1,1,m,l2,r2);
if(Maxf==-INF&&maxz) printf("%lld\n",maxz*Minz);
else if(Maxf==-INF&&minz==INF) printf("%lld\n",maxf*Maxz);
else if(Maxf==-INF&&maxz&&minf!=0) printf("%lld\n",maxz*Minz);
else if(Minz==INF&&minz==INF) printf("%lld\n",minf*Maxf);
else if(Minz==INF&&maxf==-INF) printf("%lld\n",minz*Minf);
else if(Minz==INF&&maxf!=-INF&&minz!=INF) printf("%lld\n",minf*Maxf);
else if(maxf==-INF&&Maxf!=-INF&&Minz!=INF) printf("%lld\n",minz*Minf);
else if(minz==INF&&Maxf!=-INF&&Minz!=INF) printf("%lld\n",maxf*Maxz);
else printf("%lld\n",max(maxf*Maxz,minz*Minf));
//cout<<maxz<<" "<<minz<<" "<<maxf<<" "<<minf<<" "<<Maxz<<" "<<Minz<<" "<<Maxf<<" "<<Minf<<endl;
}
return 0;
}
T3
成功颠覆我对于
40pts
发现可以发动反击的条件就是整个图是一个环,可以实现连续穿梭的条件就是这个点出度为
暴力按照题目的四种操作进行模拟即可。
#include<iostream>
using namespace std;
const int N=5e5+5;
struct node
{
int to,next,flag;
};
node edge[N];
int head[N],vis[N],outd[N],qz[1005][1005];
int n,m,num,flag;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9')
{ if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9')
{ s=s*10+ch-'0'; ch=getchar();}
return s*w;
}
void add(int u,int v)
{
++num;
qz[u][v]=num;
edge[num].to=v;
edge[num].next=head[u];
head[u]=num;
}
int dfs(int now,int tim)
{
vis[now]=tim;
for(int i=head[now];i;i=edge[i].next)
{
if(edge[i].flag) continue;
int v=edge[i].to;
if(vis[v]==tim) return 1;
if(dfs(v,tim)) return 1;
}
return 0;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
outd[u]++;
add(u,v);
}
int q=read();
while(q--)
{
int flag=1;
int t=read();
if(t==1)
{
int u=read(),v=read();
outd[u]--;
edge[qz[u][v]].flag=1;
}
if(t==2)
{
int u=read();
for(int i=1;i<=n;++i)
{
if(qz[i][u]&&!edge[qz[i][u]].flag)
{
edge[qz[i][u]].flag=1;
outd[i]--;
}
}
}
if(t==3)
{
int u=read(),v=read();
edge[qz[u][v]].flag=0;
outd[u]++;
}
if(t==4)
{
int u=read();
for(int i=1;i<=n;++i)
{
if(qz[i][u]&&edge[qz[i][u]].flag)
{
edge[qz[i][u]].flag=0;
outd[i]++;
}
}
}
for(int i=1;i<=n;++i)
{
if(vis[i]!=q&&!dfs(i,q))
{
flag=0;
break;
}
}
if(flag)
{
for(int i=1;i<=n;++i)
if(outd[i]!=1)
{
flag=0;
break;
}
if(flag==1) printf("YES\n");
else printf("NO\n");
}
else printf("NO\n");
}
return 0;
}
50pts
发现只要所有点的出度都为
维护全局答案,每次操作后判断。
#include<iostream>
#include<cstdlib>
#include<ctime>
#include<map>
using namespace std;
const int N=5e5+5;
struct node
{
int to,next,flag;
};
node edge[N];
map<int,int> qz[N];
int head[N],outd[N];
int num,n,m,cnt;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9')
{ if(ch=='-') w=-1; ch=getchar();}
while(ch>='0'&&ch<='9')
{ s=s*10+ch-'0'; ch=getchar();}
return s*w;
}
void add(int u,int v)
{
++num;
qz[u][v]=num;
edge[num].to=v;
edge[num].next=head[u];
head[u]=num;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
add(u,v);
outd[u]++;
}
for(int i=1;i<=n;++i)
if(outd[i]==1) cnt++;
int q=read();
while(q--)
{
int t=read();
if(t==1)
{
int u=read(),v=read();
edge[qz[u][v]].flag=1;
if(outd[u]==2) cnt++;
if(outd[u]==1) cnt--;
outd[u]--;
}
if(t==2)
{
int u=read();
for(int i=1;i<=n;++i)
{
if(qz[i][u]&&!edge[qz[i][u]].flag)
{
if(outd[i]==1) cnt--;
if(outd[i]==2) cnt++;
outd[i]--,edge[qz[i][u]].flag=1;
}
}
}
if(t==3)
{
int u=read(),v=read();
edge[qz[u][v]].flag=0;
if(outd[u]==1) cnt--;
if(outd[u]==0) cnt++;
outd[u]++;
}
if(t==4)
{
int u=read();
for(int i=1;i<=n;++i)
{
if(qz[i][u]&&edge[qz[i][u]].flag)
{
edge[qz[i][u]].flag=0;
if(outd[i]==1) cnt--;
if(outd[i]==0) cnt++;
outd[i]++;
}
}
}
if(cnt==n) printf("YES\n");
else printf("NO\n");
}
return 0;
}
10.3(30pts=30pts+0pts+0pts)
大寄。
感觉挺难受的。。。