小易准备去魔法王国采购魔法神器,购买魔法神器需要使用魔法币,但是小易现在一枚魔法币都没有,但是小易有两台魔法机器可以通过投入x(x可以为0)个魔法币产生更多的魔法币。
魔法机器1:如果投入x个魔法币,魔法机器会将其变为2x+1个魔法币
魔法机器2:如果投入x个魔法币,魔法机器会将其变为2x+2个魔法币
小易采购魔法神器总共需要n个魔法币,所以小易只能通过两台魔法机器产生恰好n个魔法币,小易需要你帮他设计一个投入方案使他最后恰好拥有n个魔法币。
思路:一开始DFS搜索 即使最深30层 也只拿了60分
操作一,一定使当前数变成奇数
操作二,一定使当前数变成偶数
每次对当前数进行判断 是由哪一步变来的 倒退回去即可
1 #include <cstdio> 2 #include <cctype> 3 4 const int MAXN=1000010; 5 6 int n,tot; 7 8 int a[MAXN]; 9 10 bool flag; 11 12 bool DFS(int x) { 13 if(x>n) return false; 14 if(x==n) return true; 15 if(DFS(2*x+1)) {a[++tot]=1;return true;} 16 if(DFS(2*x+2)) {a[++tot]=2;return true;} 17 return false; 18 } 19 20 int hh() { 21 scanf("%d",&n); 22 DFS(0); 23 for(int i=tot;i;--i) printf("%d",a[i]); 24 return 0; 25 } 26 27 int sb=hh(); 28 int main(int argc,char**argv) {;}
1 #include <cstdio> 2 #include <cctype> 3 4 const int MAXN=100; 5 6 int n,tot; 7 8 int a[MAXN]; 9 10 bool flag; 11 12 int hh() { 13 scanf("%d",&n); 14 while(n) { 15 if(n%2==0) { 16 a[++tot]=2; 17 n=(n-2)/2; 18 } 19 else { 20 a[++tot]=1; 21 n=(n-1)/2; 22 } 23 } 24 for(int i=tot;i;--i) printf("%d",a[i]); 25 return 0; 26 } 27 28 int sb=hh(); 29 int main(int argc,char**argv) {;}
二丶相反数
为了得到一个数的"相反数",我们将这个数的数字顺序颠倒,然后再加上原先的数得到"相反数"。例如,为了得到1325的"相反数",首先我们将该数的数字顺序颠倒,我们得到5231,之后再加上原先的数,我们得到5231+1325=6556.如果颠倒之后的数字有前缀零,前缀零将会被忽略。例如n = 100, 颠倒之后是1.
思路:倒过来与原数加一遍即可
1 #include <cstdio> 2 #include <cctype> 3 4 int n,t,len; 5 6 int a[10]; 7 8 int hh() { 9 scanf("%d",&n); 10 int k=n; 11 while(k) { 12 a[++len]=k%10; 13 k/=10; 14 } 15 int l=1; 16 for(int i=len;i;--i) t+=l*a[i],l*=10; 17 printf("%d\n",t+n); 18 return 0; 19 } 20 21 int sb=hh(); 22 int main(int argc,char**argv) {;}
三丶字符串碎片
一个由小写字母组成的字符串可以看成一些同一字母的最大碎片组成的。例如,"aaabbaaac"是由下面碎片组成的:'aaa','bb','c'。牛牛现在给定一个字符串,请你帮助计算这个字符串的所有碎片的平均长度是多少。
思路:ans=字符串长度/字符串碎片的个数
一个字符串碎片一定是由同一种字母组成 不需要考虑太多
1 #include <cstdio> 2 #include <cctype> 3 #include <cstring> 4 5 const int MAXN=1010; 6 7 int len,sum; 8 9 char s[MAXN]; 10 11 int hh() { 12 scanf("%s",s+1); 13 len=strlen(s+1); 14 for(int i=1;i<=len;++i) if(s[i]!=s[i-1]) ++sum; 15 double ans=(double)len/sum; 16 printf("%.2lf",ans); 17 return 0; 18 } 19 20 int sb=hh(); 21 int main(int argc,char**argv) {;}
四丶游历魔法王国
魔法王国一共有n个城市,编号为0~n-1号,n个城市之间的道路连接起来恰好构成一棵树。
小易现在在0号城市,每次行动小易会从当前所在的城市走到与其相邻的一个城市,小易最多能行动L次。
如果小易到达过某个城市就视为小易游历过这个城市了,小易现在要制定好的旅游计划使他能游历最多的城市,请你帮他计算一下他最多能游历过多少个城市(注意0号城市已经游历了,游历过的城市不重复计算)。
思路:分两种情况讨论
一是当小易走的步数小于树的最长链
二是当小易走的步数大于最长链
这时候 最长链是一定要走的 那剩下的步数最优的情况是走一步走过的城市 再到一个没走过的城市 再退回来 再走没走的城市
这样最多可以走(L-MAX_L)/2个城市
最后min(n,MAX_L+(L-MAX_L)/2)
DFS好像有60分
1 #include <cstdio> 2 #include <cctype> 3 #include <vector> 4 5 const int MAXN=110; 6 7 int n,l,ans; 8 9 bool vis[MAXN]; 10 11 std::vector<int> Graph[MAXN]; 12 13 void DFS(int u,int step,int mx) { 14 if(step==l) { 15 ans=mx>ans?mx:ans; 16 return; 17 } 18 for(int i=0;i<Graph[u].size();++i) { 19 int v=Graph[u][i]; 20 if(!vis[v]) vis[v]=true,DFS(v,step+1,mx+1),vis[v]=false; 21 else DFS(v,step+1,mx); 22 } 23 } 24 25 int hh() { 26 scanf("%d%d",&n,&l); 27 for(int x,i=1;i<n;++i) { 28 scanf("%d",&x); 29 ++x; 30 Graph[x].push_back(i+1); 31 Graph[i+1].push_back(x); 32 } 33 vis[1]=true; 34 DFS(1,0,0); 35 printf("%d\n",ans+1); 36 return 0; 37 } 38 39 int sb=hh(); 40 int main(int argc,char**argv) {;}
1 #include <cstdio> 2 #include <cctype> 3 #include <vector> 4 #define min(a,b) a>b?b:a 5 6 const int MAXN=110; 7 8 int n,l,ans; 9 10 int dp[MAXN],p[MAXN]; 11 12 int hh() { 13 scanf("%d%d",&n,&l); 14 for(int i=0;i<n-1;++i) scanf("%d",&p[i]); 15 16 int mx=-1; 17 for(int i=0;i<n-1;++i) { 18 dp[i+1]=dp[p[i]]+1; 19 ans=ans>dp[i+1]?ans:dp[i+1]; 20 } 21 ans=min(ans,l); 22 printf("%d\n",min(n,1+ans+(l-ans)/2)); 23 24 return 0; 25 } 26 27 int sb=hh(); 28 int main(int argc,char**argv) {;}
五丶重排数列
小易有一个长度为N的正整数数列A = {A[1], A[2], A[3]..., A[N]}。
牛博士给小易出了一个难题:
对数列A进行重新排列,使数列A满足所有的A[i] * A[i + 1](1 ≤ i ≤ N - 1)都是4的倍数。
小易现在需要判断一个数列是否可以重排之后满足牛博士的要求。
思路:我们用 1 表示 这个数是4的倍数
0 表示 这个数不是4的倍数
显然 一个合法的序列有 1 0 1 0 1 0... 或者 0 1 0 1 0 1 0....
当然 两个 同为 2的倍数 的数也可以被4整除 所以 0 1 0 1 2 2 2 2.... 这样的也是合法序列
所以统计一个数列中 4的倍数 2的倍数 和其他数的个数
不存在2的倍数时 4的倍数的个数 和不是4的倍数的个数只差1个数
存在2的倍数 则要求 4的倍数的个数要大于等于不是4的倍数的个数 否则 0 1 0 2 2 2.... 这样的序列是不合法的
1 #include <cstdio> 2 #include <cctype> 3 4 const int MAXN=100010; 5 6 int T,n,A,B,C; 7 8 int a[MAXN]; 9 10 inline void read(int&x) { 11 int f=1;register char c=getchar(); 12 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar()); 13 for(;isdigit(c);x=x*10+c-48,c=getchar()); 14 x=x*f; 15 } 16 17 int hh() { 18 read(T); 19 while(T--) { 20 read(n); 21 A=B=C=0; 22 for(int i=1;i<=n;++i) { 23 read(a[i]); 24 if(a[i]%4==0) ++A; 25 else if(a[i]%2==0) ++B; 26 else ++C; 27 } 28 int t=n/2; 29 if(t==A||n-t==A) printf("Yes\n"); 30 else { 31 if(A>=C) printf("Yes\n"); 32 else printf("No\n"); 33 } 34 } 35 return 0; 36 } 37 38 int sb=hh(); 39 int main(int argc,char**argv) {;}
六丶最长公共子括号序列
一个合法的括号匹配序列被定义为:
1. 空串""是合法的括号序列
2. 如果"X"和"Y"是合法的序列,那么"XY"也是一个合法的括号序列
3. 如果"X"是一个合法的序列,那么"(X)"也是一个合法的括号序列
4. 每个合法的括号序列都可以由上面的规则生成
例如"", "()", "()()()", "(()())", "(((()))"都是合法的。
从一个字符串S中移除零个或者多个字符得到的序列称为S的子序列。
例如"abcde"的子序列有"abe","","abcde"等。
定义LCS(S,T)为字符串S和字符串T最长公共子序列的长度,即一个最长的序列W既是S的子序列也是T的子序列的长度。
小易给出一个合法的括号匹配序列s,小易希望你能找出具有以下特征的括号序列t:
1、t跟s不同,但是长度相同
2、t也是一个合法的括号匹配序列
3、LCS(s, t)是满足上述两个条件的t中最大的
因为这样的t可能存在多个,小易需要你计算出满足条件的t有多少个。
如样例所示: s = "(())()",跟字符串s长度相同的合法括号匹配序列有:
"()(())", "((()))", "()()()", "(()())",其中LCS( "(())()", "()(())" )为4,其他三个都为5,所以输出3.
思路:要求LCS最大 那么只改变一个位置的序列的LCS最大
每次只挖出一个字符 把它插入不同的位置 判断是否为合法的序列
统计个数 最后再减去原序列
1 #include <set> 2 #include <cstdio> 3 #include <cctype> 4 #include <iostream> 5 6 using namespace std; 7 8 int len; 9 10 string s; 11 12 set<string> Set; 13 14 inline bool judge(string u) { 15 int q=0; 16 for(int i=0;i<len;++i) { 17 if(u[i]=='(') ++q; 18 else { 19 if(q==0) return false; 20 else --q; 21 } 22 } 23 if(!q) return true; 24 else return false; 25 } 26 27 int hh() { 28 cin>>s; 29 len=s.length(); 30 for(int i=0;i<len;++i) { 31 string p=s.substr(0,i)+s.substr(i+1); 32 for(int j=0;j<len-1;++j) { 33 string u=p.substr(0,j)+s[i]+p.substr(j); 34 if(judge(u)) Set.insert(u); 35 } 36 } 37 printf("%d\n",(int)Set.size()-1); 38 return 0; 39 } 40 41 int sb=hh(); 42 int main(int argc,char**argv) {;}
七丶合唱
小Q和牛博士合唱一首歌曲,这首歌曲由n个音调组成,每个音调由一个正整数表示。
对于每个音调要么由小Q演唱要么由牛博士演唱,对于一系列音调演唱的难度等于所有相邻音调变化幅度之和, 例如一个音调序列是8, 8, 13, 12, 那么它的难度等于|8 - 8| + |13 - 8| + |12 - 13| = 6(其中||表示绝对值)。
现在要对把这n个音调分配给小Q或牛博士,让他们演唱的难度之和最小,请你算算最小的难度和是多少。
如样例所示: 小Q选择演唱{5, 6}难度为1, 牛博士选择演唱{1, 2, 1}难度为2,难度之和为3,这一个是最小难度和的方案了。
思路:动态规划
dp[i][j]表示 当前演唱到第i个音符 上一个人唱到第j个音符 的最小难度和
转移则为
dp[i][j] = dp[i-1][j] + abs(v[i] - v[i-1]), j < i - 1 (当前演唱者连续演唱第i-1个音符和第i个音符)
dp[i][i -1] = min{ dp[i-1][k] + abs(v[i] - v[k]) }, k < i - 1 (当前演唱者只唱第i个音符,第i-1个音符是由上一个人唱的)
边界
一个人唱第一个音符 另一个人唱其他所有的音符 dp[i][0]=dp[i-1][0]+cost[i] (i>=2)
一个人唱前面的所有音符 另一个人唱最后一个音符 dp[i][i-1]=dp[i-1][i-2]+cost[i] (i>=2)
1 #include <cstdio> 2 #include <cctype> 3 #include <cstdlib> 4 #define min(a,b) a>b?b:a 5 #define max(a,b) a>b?a:b 6 7 typedef long long LL; 8 9 const int MAXN=2010; 10 11 int n; 12 13 int a[MAXN],cost[MAXN]; 14 15 LL dp[MAXN][MAXN]; 16 17 inline void read(int&x) { 18 int f=1;register char c=getchar(); 19 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar()); 20 for(;isdigit(c);x=x*10+c-48,c=getchar()); 21 x=x*f; 22 } 23 24 int hh() { 25 read(n);read(a[0]); 26 for(int i=1;i<n;++i) read(a[i]),cost[i]=abs(a[i]-a[i-1]); 27 28 for(int i=2;i<n;++i) 29 dp[i][0]=dp[i-1][0]+cost[i], 30 dp[i][i-1]=dp[i-1][i-2]+cost[i-1]; 31 for(int i=2;i<n;++i) 32 for(int j=0;j<i-1;++j) { 33 dp[i][j]=dp[i-1][j]+cost[i]; 34 dp[i][i-1]=min(dp[i][i-1],dp[i-1][j]+abs(a[i]-a[j])); 35 } 36 LL ans=(1ll<<63)-1; 37 for(int i=0;i<n-1;++i) ans=min(ans,dp[n-1][i]); 38 39 printf("%lld\n",ans); 40 return 0; 41 } 42 43 int sb=hh(); 44 int main(int argc,char**argv) {;}
八丶射击游戏
小易正在玩一款新出的射击游戏,这个射击游戏在一个二维平面进行,小易在坐标原点(0,0),平面上有n只怪物,每个怪物有所在的坐标(x[i], y[i])。小易进行一次射击会把x轴和y轴上(包含坐标原点)的怪物一次性消灭。
小易是这个游戏的VIP玩家,他拥有两项特权操作:
1、让平面内的所有怪物同时向任意同一方向移动任意同一距离
2、让平面内的所有怪物同时对于小易(0,0)旋转任意同一角度
小易要进行一次射击。小易在进行射击前,可以使用这两项特权操作任意次。
1 #include <cstdio> 2 #include <cctype> 3 4 const int MAXN=110; 5 6 int n,ans; 7 8 int x[MAXN],y[MAXN]; 9 10 inline void read(int&x) { 11 int f=1;register char c=getchar(); 12 for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar()); 13 for(;isdigit(c);x=x*10+c-48,c=getchar()); 14 x=x*f; 15 } 16 17 int hh() { 18 read(n); 19 for(int i=1;i<=n;++i) read(x[i]); 20 for(int i=1;i<=n;++i) read(y[i]); 21 if(n<=3) {printf("%d\n",n);return 0;} 22 for(int i=1;i<=n;++i) 23 for(int j=1;j<=n;++j) { 24 if(i==j) continue; 25 for(int k=1;k<=n;++k) { 26 if(k==i||k==j) continue; 27 int t=0; 28 for(int l=1;l<=n;++l) { 29 if(l==k||l==i||l==j) continue; 30 if((x[k]-x[l])*(x[j]-x[i])==(y[l]-y[k])*(y[j]-y[i])) ++t; 31 else if((x[l]-x[i])*(y[l]-y[j])==(x[l]-x[j])*(y[l]-y[i])) ++t; 32 } 33 ans=t>ans?t:ans; 34 } 35 } 36 printf("%d\n",ans+3); 37 return 0; 38 } 39 40 int sb=hh(); 41 int main(int argc,char**argv) {;}