Link
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}>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$:我躺着也中枪) 发现:并联其实就是取倒数。。。 那么就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| #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'); } }
int a,b,ans=0; signed main(){
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; }
|
B. 「NOIP模拟赛」找零
题意
由$n$种硬币,每种面值的硬币有无数个。 希望用最少的硬币组合出$1\sim x$的任意值。 问最少需要多少硬币?
思路
考虑已经能组合出$1\sim x$的数值 那么下一个硬币取$x$以内最大的数$k$ 使能组合出$1\sim x+k$ 那么就用$upper\text{_}bound$就好了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #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'); } }
int n,a[1000010],x,now,ans; signed main(){
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$乘起来就好了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| #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'); } }
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(){
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;
MaxSum=min(1ll*2048,MaxSum+a[i]); }else{ ans++; } } write((fpow(2,ans)*f[2048])%mod);putchar('\n'); return 0; }
|