NOIP模拟赛多校联考——Round7题解
整数分解
题意
对任意数求分解为2的幂之和有多少种分法。
思路
奇怪的递推。。。手玩小样例得知答案序列为n级等差数列。。。貌似碾标算
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T> inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T> inline void write (T x) {
if (x<0) putchar('-');
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve {
const int N=1000001;
const int MOD=1000000007;
int n;
int ans[N];
inline void MAIN () {
read(n);
ans[0]=1,ans[2]=2;
for (register int i=4; i<=n; i+=2) {
ans[i]=(ans[i-2]+ans[((i/2)%2)?i/2-1:i/2])%MOD;
}
write(ans[(n%2)?n-1:n]);
}
}
int main () {
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
Solve::MAIN();
}
贫富差距
题意
一个国家有N个公民,标记为0,1,2,...,N−1,每个公民有一个存款额。已知每个公民有一些朋友,同时国家有一条规定朋友间的存款额之差不能大于d。也就是说,a 和 b 是朋友的话,a 有 x 元的存款,b 有 y 元,那么\(|x-y|\leq d\)给定d值与N个人的朋友关系,求这个国家最富有的人和最贫穷的人的存款相差最大的可能值是多少?即求贫富差距的最大值的下界。若这个值为无穷大,输出-1.
思路
暴搜
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T> inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T> inline void write (T x) {
if (x<0) putchar('-');
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve {
const int N=55;
const int INF=2147483647;
int T;
int n,d,cnt;
char c;
int tot;
int head[N];
struct node {
int to,next;
} edge[N*N];
int ans,maxp,minp;
int conn[N];
int vis[N],colors[N];
int fa[N];
inline void add (int a,int b) {
edge[++tot].to=b,edge[tot].next=head[a],head[a]=tot;
}
// void dfs (int now,int dep) {
// tmp=max(tmp,dep),vis[now]=1;
// for (register int i=head[now]; i; i=edge[i].next) {
// int to=edge[i].to;
// if (vis[to]) continue;
// dfs(to,dep+1);
// }
// }
// void color (int now,int col,int lim) {
// colors[now]=min(col,lim);
// for (register int i=head[now]; i; i=edge[i].next) {
// int to=edge[i].to;
// if (colors[to]!=-1) continue;
// if (conn[to]==2&&col+d>lim) colors[to]=INF;
// else color(to,col+d,lim);
// }
// }
void color (int now,int lim) {
queue<pair<int,int> > q;
while (q.size()) q.pop();
colors[now]=0;
for (register int i=head[now]; i; i=edge[i].next) {
int to=edge[i].to;
q.push(make_pair(now,to));
}
while (q.size()) {
pair<int,int> cur=q.front();q.pop();
if (colors[cur.second]!=-1) continue;
colors[cur.second]=min(colors[cur.first]+d,lim);
for (register int i=head[cur.second]; i; i=edge[i].next) {
int to=edge[i].to;
if (colors[to]!=-1) continue;
q.push(make_pair(cur.second,to));
}
}
}
bool dfs (int now,int lim) {
vis[now]=1,maxp=max(maxp,colors[now]),minp=min(minp,colors[now]);
for (register int i=head[now]; i; i=edge[i].next) {
int to=edge[i].to;
if (abs(colors[to]-colors[now])>d) return false;
if (vis[to]) continue;
if (!dfs(to,lim)) return false;
}
return true;
}
int find (int x) {
return x==fa[x]?fa[x]:fa[x]=find(fa[x]);
}
inline void MAIN () {
read(T);
while (T--) {
read(n),read(d);
cnt=tot=0,ans=0;
memset(head,0,sizeof(head)),memset(conn,0,sizeof(conn));
for (register int i=1; i<=n; ++i) fa[i]=i;
for (register int i=1; i<=n; ++i) {
for (register int j=1; j<=n; ++j) {
cin>>c,cnt+=(c=='Y');
if (c=='Y') {
add(i,j),++conn[i],++conn[j];
if (fa[find(i)]!=find(j)) fa[find(i)]=find(j);
}
}
}
for (register int i=1; i<=n; ++i) {
if (find(i)!=find(1)) {
cnt=0;
}
}
if (cnt==0) {
puts("-1");
} else {
int flag=0;
for (register int x=d*(n-1); x>=d; x-=d) {
for (register int i=1; i<=n; ++i) {
memset(vis,0,sizeof(vis)),minp=INF,maxp=0;
for (register int j=1; j<=n; ++j) colors[j]=-1;
color(i,x);
if (dfs(i,x)) {
ans=max(ans,maxp-minp),flag=1;
// break;
}
}
if (flag==1) break;
}
write(ans),putchar('\n');
// for (register int i=1; i<=n; ++i) {
// tmp=0;
// memset(vis,0,sizeof(vis));
// dfs(i,1);
// ans=min(ans,tmp);
// }
// write(d*ans),putchar('\n');
}
}
}
}
int main () {
// freopen("1.in","r",stdin);
// freopen("2.out","w",stdout);
Solve::MAIN();
}
特殊的排列
题意
将一个打乱的数列复原,每次可以调动一个数的位置,求最少次数。
思路
LIS
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T> inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T> inline void write (T x) {
if (x<0) putchar('-');
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve {
const int N=100050;
int n;
int a[N],pos[N],len[N];
inline void MAIN () {
read(n);
for (register int i=1; i<=n; ++i) {
read(a[i]),pos[a[i]]=i;
}
for (register int i=1; i<=n; ++i) {
if (a[i]==1) len[a[i]]=1;
else {
if (pos[a[i]-1]>pos[a[i]]) len[a[i]]=1;
else len[a[i]]=len[a[i]-1]+1;
}
}
int ans=0;
for (register int i=1; i<=n; ++i) {
ans=max(ans,len[i]);
}
write(n-ans);
}
}
int main () {
// freopen("1.in","r",stdin);
// freopen("2.out","w",stdout);
Solve::MAIN();
}
极品飞车
题意
有一辆速度表不准的车,当表盘读数为 s 时,真实车速为 s + c,c 为任意实数常量,且可能是负数。 这辆车依次通过了 n 段道路,总共花费了 t 的时间, 其中 第 i 段道路的长度为 di,表盘读数一直为 si。 已知这些信息,请求出实数常量 c。
思路
二分裸题
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T> inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T> inline void write (T x) {
if (x<0) putchar('-');
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve {
const int N=1001;
const double eps=0.000000001;
int n;
double t;
double d[N],s[N];
double ans;
inline double tim (double x) {
double res=0.0;
for (register int i=1; i<=n; ++i) {
res+=d[i]/(s[i]+x);
}
return res;
}
inline void MAIN () {
read(n),read(t);double minn=1001;
for (register int i=1; i<=n; ++i) {
read(d[i]),read(s[i]);
minn=min(minn,s[i]);
}
double l=-minn+eps,r=3000000.0,mid;
while (r-l>eps) {
mid=(l+r)/2;
if (tim(mid)>t) l=mid;
else r=mid;
}
printf("%.6lf",mid);
}
}
int main () {
// freopen("1.in","r",stdin);
// freopen("2.out","w",stdout);
Solve::MAIN();
}
修改数组
题意
给出一个整数数组 A,你可以将任何一个数修改为任意一个正整数,最终使得整个数组是严格递增的且均为正整数。问最少需要修改几个数?
思路
LIS
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T> inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T> inline void write (T x) {
if (x<0) putchar('-');
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve {
const int N=100100;
const int INF=2147483647;
int n,ans,top;
int a[N],s[N];
inline void MAIN () {
read(n);
for (register int i=1; i<=n; ++i) {
read(a[i]),a[i]-=i;
}
for (register int i=1; i<=n; ++i) {
if (a[i]<0) continue;
else {
if (a[i]>=s[top]) s[++top]=a[i];
else {
s[upper_bound(s+1,s+top+1,a[i])-s]=a[i];
}
}
}
write(n-top);
}
}
int main () {
// freopen("1.in","r",stdin);
// freopen("2.out","w",stdout);
Solve::MAIN();
}
小Biu看电影
题意
无聊的小 Biu 来到了电影之城,他发现这里有 n 个电影院,而且每个电影院的电影票价是不同的,有一些电影院之间有双向联通的道路,想要通过某条道路需要两倍的花费,小 Biu 想知道,他以每一个电影院为起点(当然也可以原地不动),最少需要多少花费可以看到电影。
思路
建个超级原点,跑dijk。
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T> inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T> inline void write (T x) {
if (x<0) putchar('-');
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Solve {
const int N=100001;
int n,m;
int val[N];
int cnt;
int head[N];
struct node {
int to,next,val;
} edge[N*3];
int dis[N],vis[N];
inline void add (int a,int b,int c) {
edge[++cnt].to=b,edge[cnt].val=c,edge[cnt].next=head[a],head[a]=cnt;
}
inline void dij (int s) {
int cur=s;
dis[cur]=0;
while (!vis[cur]) {
vis[cur]=1;
int minn=2147483647,minj;
for (register int i=head[cur]; i; i=edge[i].next) {
int to=edge[i].to;
dis[to]=min(dis[to],dis[cur]+edge[i].val);
}
for (register int i=1; i<=n; ++i) {
if (vis[i]) continue;
if (minn>dis[i]) minn=dis[i],minj=i;
}
cur=minj;
}
}
inline void MAIN () {
read(n),read(m);
for (register int i=1; i<=n; ++i) {
read(val[i]);
add(0,i,val[i]);
}
for (register int i=1,x,y,z; i<=m; ++i) {
read(x),read(y),read(z);
add(x,y,z*2),add(y,x,z*2);
}
for (register int i=0; i<=n; ++i) dis[i]=2147483647;
dij(0);
for (register int i=1; i<=n; ++i) {
write(dis[i]),putchar('\n');
}
}
}
int main () {
// freopen("1.in","r",stdin);
// freopen("2.out","w",stdout);
Solve::MAIN();
}