NOIP2019模拟赛(五)03.31 解题报告

Link

NOIP2019模拟赛(五)03.31

A. 「NOIP模拟赛」电阻

题意

询问要得出一个电阻值为$\frac{a}{b}$的元件至少需要多少个电阻值为$1$的电阻。

元件由$3$种方式组成:

  1. 一个电阻
  2. 一个元件与一个电阻串联
  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}>1$,所以这肯定是两个元件串联而成的,其中一个元件的阻值为$1$,另外一个元件的阻值为$\frac{4}{7}$。

其中的一个元件阻值为$1$,思考:那么如果是更大的数呢?其实也差不多,就是若干个电阻值为$1$的电阻串联起来的,因为分成的这部分的电阻值其实为整数

另外的一个元件阻值为$\frac{4}{7}$,因为$\frac{4}{7}<1$,所以它是由两个元件并联而成的,我们可以对它取倒数(根据并联公式),得到$\frac{7}{4}=1+\frac{3}{4}$,继续拆分$\frac{3}{4}$,可得$\frac{3}{4}<1$,那么再倒数,得到$\frac{4}{3}=1+\frac{1}{3}$,然后继续拆分$\frac{1}{3}$,可得$\frac{1}{3}<1$,再倒数可得$3$,因为这已经不是分数,而是整数了,那么就不需要继续拆分了。

然后会很惊奇的发现,这个过程很像$gcd$。($gcd$:我躺着也中枪)

发现:并联其实就是取倒数。。。

那么就好了。

#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%10+'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$种硬币,每种面值的硬币有无数个。

希望用最少的硬币组合出$1\sim x$的任意值。

问最少需要多少硬币?

思路

考虑已经能组合出$1\sim x$的数值

那么下一个硬币取$x$以内最大的数$k$

使能组合出$1\sim x+k$

那么就用$upper\text{_}bound$就好了

#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%10+'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$乘起来就好了

#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%10+'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;
}

评论

  1. yzx1798106406 博主
    2年前
    2019-3-31 16:09:00

    hhh

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇