NOIP2019模拟赛(五)03.31 解题报告
Link
NOIP2019模拟赛(五)03.31
A. 「NOIP模拟赛」电阻
题意
询问要得出一个电阻值为frac{a}{b}的元件至少需要多少个电阻值为1的电阻。 元件由3种方式组成:
- 一个电阻
- 一个元件与一个电阻串联
- 一个元件与一个电阻并联
思路
并联电阻阻值计算
总电阻值为:总R_总=frac{1}{frac{1}{R_1]} frac{1}{R_2]} … frac{1}{R_n]}} 特别的,两个电阻并联总值为:R=frac{R_1R_2}{R_1 R_2}
串联电阻阻值计算
(不要问我为什么我把电阻搞成了灯泡,凑合着看吧) 总电阻值为:总R_总=R_1 R_2 … R_n
回归到这道题目
考虑一组较为简单的样例,R=frac{11}{7}Omega 由于frac{11}{7}>11,另外一个元件的阻值为frac{4}{7}。 其中的一个元件阻值为1,思考:那么如果是更大的数呢?其实也差不多,就是若干个电阻值为1的电阻串联起来的,因为分成的这部分的电阻值其实为整数。 另外的一个元件阻值为frac{4}{7},因为frac{4}{7}<1frac{7}{4}=1 frac{3}{4},继续拆分frac{3}{4},可得frac{3}{4}<1frac{4}{3}=1 frac{1}{3},然后继续拆分frac{1}{3},可得frac{1}{3}<13,因为这已经不是分数,而是整数了,那么就不需要继续拆分了。 然后会很惊奇的发现,这个过程很像gcd。(gcd:我躺着也中枪) 发现:并联其实就是取倒数。。。 那么就好了。
代码语言:javascript复制#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define int long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(ch<'0'ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10 ch-'0',ch=getchar();
return res*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x '0');
else{
write(x/10);
putchar(x '0');
}
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
int a,b,ans=0;
signed main(){
// freopen("A.in","r",stdin);freopen("A.out","w",stdout);
a=read();b=read();
while(a!=0&&b!=0){
if(a<b) swap(a,b);
ans =a/b;
a%=b;
}
write(ans);putchar('n');
return 0;
}
//并联:1/(1/R[1] 1/R[2] ... 1/R[n])
//串联:R[1] R[2] ... R[n]
//并联2:(R[1]*R[2])/(R[1] R[2])
B. 「NOIP模拟赛」找零
题意
由n种硬币,每种面值的硬币有无数个。 希望用最少的硬币组合出1sim x的任意值。 问最少需要多少硬币?
思路
考虑已经能组合出1sim x的数值 那么下一个硬币取x以内最大的数k 使能组合出1sim x k 那么就用uppertext{_}bound就好了
代码语言:javascript复制#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define int long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(ch<'0'ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10 ch-'0',ch=getchar();
return res*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x '0');
else{
write(x/10);
putchar(x '0');
}
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
int n,a[1000010],x,now,ans;
signed main(){
// freopen("%name%.in","r",stdin);freopen("%name%.out","w",stdout);
x=read();n=read();
for(int i=1;i<=n;i ) a[i]=read();
sort(a 1,a n 1);
if(a[1]!=1){
puts("-1");
return 0;
}
while(now<x){
int tmp=upper_bound(a 1,a n 1,now 1)-a-1;
ans ;
now =a[tmp];
}
write(ans);putchar('n');
return 0;
}
C. 「NOIP模拟赛」2048
题意
给定一个长度为n的数列,在这个数列中选取一个子序列使得这个子序列中的数能合出2048 对于合并操作,可以选择这个序列中的任意两个数进行合并,当然这两个数必须是相同的(即2个x合并后成为一个2x) 对于每个序列,只要进行若干次合并操作后,这个序列中至少有一个2048(可以有其他数剩余),就称这个序列是合法的 我们可以认为只要选取的数在原数列中的位置不同,这些序列就是不同的 对于给定的数列,小朋友们需要算出有多少子序列是合法的,并把这个数 对998244353取模
思路
因为合并时两个数必须是相同的,且合并出2048=2^{11} 那么可想而知,合并的几个数必须是2的幂。 所以就把所有2的幂弄在一起,搞个dp求一下有多少种可能之和不小于2048。 然后其他不是2的幂的数字可以剩余,所以可有可无,那么就统计一下求一下2^{count}(因为有无共两种情况,乘法原理) 最后把两部分的ans乘起来就好了
代码语言:javascript复制#include<algorithm>
#include<bitset>
#include<complex>
#include<deque>
#include<exception>
#include<fstream>
#include<functional>
#include<iomanip>
#include<ios>
#include<iosfwd>
#include<iostream>
#include<istream>
#include<iterator>
#include<limits>
#include<list>
#include<locale>
#include<map>
#include<memory>
#include<new>
#include<numeric>
#include<ostream>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<stdexcept>
#include<streambuf>
#include<string>
#include<typeinfo>
#include<utility>
#include<valarray>
#include<vector>
#include<cctype>
#include<cerrno>
#include<cfloat>
#include<ciso646>
#include<climits>
#include<clocale>
#include<cmath>
#include<csetjmp>
#include<csignal>
#include<cstdarg>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define mod 998244353
#define int long long
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(ch<'0'ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') res=res*10 ch-'0',ch=getchar();
return res*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x '0');
else{
write(x/10);
putchar(x '0');
}
}
//queue<int> q;
//set<int> s;
//priority_queue<int> q1;
//priority_queue<int,vector<int>,greater<int> > q2;
//list<int> l;
//stack<int> s;
int n,a[100010],f[2050],ans=0,Pow[2050],MaxSum;
int fpow(int a,int b){
if(b==0) return 1ll;
if(b==1) return a;
int res=fpow(a,b/(2*1ll));
if(b&(1ll)) return res*res%mod*a%mod;
else return res*res%mod;
}
signed main(){
// freopen("C.in","r",stdin);freopen("C.out","w",stdout);
n=read();
for(int i=1;i<=n;i ) a[i]=read();
sort(a 1,a n 1);
memset(f,0,sizeof(f));
Pow[1]=1;
Pow[2]=1;
Pow[4]=1;
Pow[8]=1;
Pow[16]=1;
Pow[32]=1;
Pow[64]=1;
Pow[128]=1;
Pow[256]=1;
Pow[512]=1;
Pow[1024]=1;
Pow[2048]=1;
f[0]=1;
for(int i=1;i<=n;i ){
if(Pow[a[i]]==1){
for(int j=MaxSum;j>=0;j--) f[min(j a[i],1ll*2048)] =f[j],f[min(j a[i],1ll*2048)]%=mod;
// cout<<Max<<" "<<a[i]<<endl;
MaxSum=min(1ll*2048,MaxSum a[i]);
}else{
ans ;
}
}
write((fpow(2,ans)*f[2048])%mod);putchar('n');
return 0;
}