2022年寒假ACM练习2(待补题)

这次的题目有点太难了,很多都没做出来,以后补题。

题目

A——手机键盘

题目描述
按照手机键盘输入字母的方式,计算所花费的时间 如:a,b,c都在“1”键上,输入a只需要按一次,输入c需要连续按三次。
如果连续两个字符不在同一个按键上,则可直接按,如:ad需要按两下,kz需要按6下。
如果连续两字符在同一个按键上,则两个按键之间需要等一段时间,如ac,在按了a之后,需要等一会儿才能按c。
现在假设每按一次需要花费一个时间段,等待时间需要花费两个时间段。
现在给出一串字符,需要计算出它所需要花费的时间。
输入
一个长度不大于100的字符串,其中只有手机按键上有的小写字母。
输出
输入可能包括多组数据,对于每组数据,输出按出Input所给字符串所需要的时间。
样例输入
bob
www
样例输出
7
7

分析:一道模拟题,但是。。。如果不知道9键盘长啥样可能就得凉。原先的9键盘从2开始才有了abc,但是我们为了顺从题意,把这里的九键盘改成八键盘,具体如下:
1——abc
2——def
3——ghi
4——jkl
5——mno
6——pqrs
7——tuv
8——wxyz

如上就是键盘的模样,剩下就是实现模拟了:
1.我们首先是要知道打每个字母时要按的次数,如果是’s’和’z’明显需要连按4下,如是’s’之前的任意一个字母,我们只需要把这个字母减去’a’得到下标再+1,然后取余3就可以啦,比如字母d,‘d’-‘a’+1等于4,取余3就知道是1了,只需要在键盘下按两下就好啦。再比如f,做如上运算取余是为0的,这时候我们只需要写个if语句 认定为在键盘上按了3下就好啦;如果是’s’之后’z’之前的字母,由于6键盘和前面5个键盘不一样(6号键盘有4个字母),因此运算规则当然要改变,直接把该字母减去’a’后再取余3就好了,取余结果为0的运算方式相同。
2.下一步就是要模拟出间隔时间,只需判断连续两次按字母是否在同一个键盘上即可。如果是’s’或’z’,显然直接判断出分别在6和8键盘,如果是’s’之前的字符,直接减去’a’后除以3再加1;如果是’s’之后’z’之前的字符,直接减去’a’再减去1后除以3再加1。我们可以好好观察这个键盘发现这个规律,当然,我可能把这个规律想复杂了,代码也能ac,模拟出来就行。

代码如下:

#include<bits/stdc++.h>
using namespace std;
int main(){
    string s;
    int a,b;
    while(cin>>s){
        int t=0;
        for(int i=0;i<s.size();i++){
            if(s[i]=='s'||s[i]=='z')t+=4;
            else if(s[i]<'s'){
                if((s[i]-'a'+1)%3==0)t+=3;
                else t+=(s[i]-'a'+1)%3;
            }
            else{
                if((s[i]-'a')%3==0)t+=3;
                else t+=(s[i]-'a')%3;
            }
            if(i!=0){
                if(s[i]=='s')a=6;
                else if(s[i]=='z')a=8;
                else if(s[i]<'s')a=(s[i]-'a')/3+1;
                else a=(s[i]-'a'-1)/3+1;
                if(s[i-1]=='s')b=6;
                else if(s[i-1]=='z')b=8;
                else if(s[i-1]<'s')b=(s[i-1]-'a')/3+1;
                else b=(s[i-1]-'a'-1)/3+1;
                if(a==b)t+=2;
            }
        }
        printf("%d\n",t);
    }
}

B——买房

题目描述
某程序员开始工作,年薪N万,他希望在中关村公馆买一套60平米的房子,现在价格是200万。
假设房子价格以每年百分之K增长,并且该程序员未来年薪不变,且不吃不喝,不用交税。
每年所得N万全都积攒起来,问第几年能够买下这套房子(第一年房价200万,收入N万)。
输入
有多行,每行两个整数N(10<=N<=50), K(1<=K<=20)。
输出
针对每组数据,如果在第21年或者之前就能买下这套房子,则输出一个整数M,表示最早需要在第M年能买下,否则输出Impossible,输出需要换行。
样例输入
50 10
40 10
40 8
样例输出
8
Impossible
10

按题意模拟一下即可,直接上代码
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
    int i,n,k;
    double m,s;
    while(cin>>n>>k){
        s=200;
        for(i=1;n*i<s;i++){
            if(i==22)break;
            m=s*0.01*k;
            s+=m;
            if(n<m)break;
        }
        if(n*i<s||i==22){
            cout<<"Impossible"<<endl;
            continue;
        }
        else if(i<=21&&n*i>=s)cout<<i<<endl;
    }
}

C——与7相关的数

题目描述
一个正整数,如果它能被7整除,或者它的十进制表示法中某个位数上的数字为7, 则称其为与7相关的数。
现求所有小于等于n(n<100)的与7无关的正整数的平方和。
输入
案例可能有多组。对于每个测试案例输入为一行,正整数n,(n<100)。
输出
对于每个测试案例输出一行,输出小于等于n的与7无关的正整数的平方和。
样例输入
21
样例输出
2336

分析:这题想要模拟和7有关的数太简单了,题目都说了n小于100了,范围又小,不用提前打表也能ac。

代码如下:

#include<bits/stdc++.h>
using namespace std;
bool judge(int n){
    if(n%7==0||n%10==7||n/10%10==7)return true;
    else return false;
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        int num=0;
        for(int i=1;i<=n;i++)
            if(!judge(i))num+=i*i;
        printf("%d\n",num);
    }
}

D——采药

题目描述
辰辰是个很有潜能、天资聪颖的孩子,他的梦想是称为世界上最伟大的医师。
为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。
医师把他带到个到处都是草药的山洞里对他说: “孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。
我会给你一段时间,在这段时间里,你可以采到一些草药。
如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入
输入的第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),T代表总共能够用来采药的时间,M代表山洞里的草药的数目。
接下来的M行每行包括两个在1到100之间(包括1和100)的的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出
可能有多组测试数据,对于每组数据,输出只包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
样例输入
70 3
71 100
69 1
1 2
样例输出
3

分析:这题实际上就是一道01背包的板子题,我这里是用的滚动数组,节省了空间,有关背包问题的解法可以看我以前的一篇长文总结:
算法学习-背包问题

代码如下:

#include<bits/stdc++.h>
using namespace std;
int t[105],v[105],f[1005];
int main(){
    int T,M;
    while(~scanf("%d%d",&T,&M)){
        memset(f,0,sizeof(f));
        for(int i=1;i<=M;i++)scanf("%d%d",&t[i],&v[i]);
        for(int i=1;i<=M;i++)
            for(int j=T;j>=t[i];j--)
                f[j]=max(f[j],f[j-t[i]]+v[i]);
        printf("%d\n",f[T]);
    }
}

E——鸡兔同笼

题目描述
一个笼子里面关了鸡和兔子(鸡有2只脚,兔子有4只脚,没有例外)。
已经知道了笼子里面脚的总数a,问笼子里面至少有多少只动物,至多有多少只动物。
输入
每组测试数据占1行,每行一个正整数a (a < 32768)。
输出
输出包含n行,每行对应一个输入,包含两个正整数,第一个是最少的动物数,第二个是最多的动物数,两个正整数用一个空格分开。
如果没有满足要求的答案,则输出两个0。
样例输入
2
3
20
样例输出
0 0
5 10

模拟一下就好啦!

代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
  int sum,min,max,n
  scanf("%d",&n);
  for(int i=0;i<n;i++){
  	scanf("%d",&sum);
  	if(sum%2==0)max=sum/2;
  	else max=0;
  	if(sum%4==0)min=sum/4;
  	else{
  		if(sum%4==2)min=sum/4+1;
  		else min=0;
  	}
  	printf("%d %d\n",min,max);
   }
}

F——为了虫群(待补题)

题目描述
小 Y 率领的人类的部队已经踏上了异虫的基地——查尔星。 作为异虫的首脑,你决定派出爆虫来迎击人类的部队。

爆虫身上长有充满酸液的囊。当它接近敌人时,会触发体内的不稳定化学物质进行反应,将自身引爆,向外泼洒强酸。自爆会摧毁爆虫,但同时也会对半径 R 之内(包括 距离为 R 的点 )的敌人造成大量伤害。

你观察到,人类有 n 名陆战队员,站成一条直线。 每个陆战队员的坐标是 xi。你有 k 个爆虫。爆虫的酸液会对陆战队员造成巨大伤害,将其瞬间消灭。 你可以把每只爆虫安排在直线上的任意位置,然后引爆,从而消灭距离该爆虫不超过 R 的所有陆战队员。

为了消灭所有 n 个陆战队员,你需要计算,爆虫的爆炸半径 R 至少要多少。
输入
输入共两行。第一行是用空格隔开的两个整数 n 和 k。

第二行是用空格隔开的 n 个实数,表示每个陆战队员的坐标 xi。所有坐标按升序给出。(可能存在某个位置有多名队员)
1≤k<n≤100,000

-107≤xi≤107

输出
输出共一行。爆虫的最小爆炸半径 R。保留 6 位小数。
样例输入
5 2
-10.0 -6.0 10 11 15
样例输出
2.500000

G——找宝箱(待补题)

题目描述
作为一个强迫症患者,小明在走游戏里的迷宫时一定要把所有的宝箱收集齐才肯罢休。

现在给你一个 N×M 的迷宫,里面有障碍、空地和宝箱,小明在某个起始点,每一步小明可以往上、下、左、右走,当然前提是没有走出迷宫并且走到的点不是障碍。如果小明走到了某个为宝箱的点,那么这个宝箱就被他收集到了,然后此处变为空地。

现在你需要计算小明最少需要走多少步才能收集齐所有的宝箱。
输入
输入共有两行。

第一行一个两个正整数 N 和 M,表示迷宫大小。

接下来 N 行,每行 M 个整数,第 i+1 行的第 j 个整数表示迷宫第 i 行第 j 列的情况, 0 表示空地,-1 表示障碍,1 表示宝箱,2 表示小明的起始点。保证 2 只有一个。

1≤N,M≤100,宝箱个数不超过5个。
输出
一行一个整数,表示小明最少的步数。如果无法收集齐所有宝箱,输出-1。
样例输入
3 5
1 -1 1 -1 2
0 -1 0 -1 0
0 0 0 0 0
样例输出
12

H——gcd区间

题目描述
给定一行 n 个正整数 a[1]…a[n]。

m 次询问,每次询问给定一个区间[L,R],输出 a[L]…a[R]的最大公因数。
输入
第一行两个整数 n,m。

第二行 n 个整数表示 a[1]…a[n]。

以下 m 行,每行 2 个整数表示询问区间的左右端点。

保证输入数据合法。

1 <= n <= 1000,1 <= m <= 1,000,000 0 < 数字大小 <= 1,000,000,000

输出
共 m 行,每行表示一个询问的答案。
样例输入
5 3
4 12 3 6 7
1 3
2 3
5 5
样例输出
1
3
7

分析:首先要明确这是要做动态规划,用dp[i][j]表示i到j范围内的最大公因数,很明显dp[i][j]等于dp[i][j-1]和a[j]的最大公因数,现在最大的问题是,用传统的求最大公因数的方法肯定超时了,那么太暴力了,一种高效的方法是我们中学时间接触到的辗转相除法,具体可以看下篇文章,是我曾经遇到过的辗转相除的例子:
HNUCM 1388——高中数学

代码如下:

#include<bits/stdc++.h>
using namespace std;
int n,m,a[1005],dp[1005][1005],l,r;
int gcd(int a,int b){
    if(b==0)return a;
    else return gcd(b,a%b);
}
int main(){
 	scanf("%d%d",&n,&m);
 	for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        dp[i][i]=a[i];
    }
    for(int i=1;i<=n;i++)
        for(int j=i;j<n;j++)
            dp[i][j+1]=gcd(dp[i][j],a[j+1]);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&l,&r);
        printf("%d\n",dp[l][r]);
    }
}

I——小白鼠

题目描述
N只小白鼠(1 <= N <= 100),每只鼠头上戴着一顶有颜色的帽子。
现在称出每只白鼠的重量,要求按照白鼠重量从大到小的顺序输出它们头上帽子的颜色。
帽子的颜色用“red”,“blue”等字符串来表示。
不同的小白鼠可以戴相同颜色的帽子。白鼠的重量用整数表示。
输入
多案例输入,每个案例的输入第一行为一个整数N,表示小白鼠的数目。
下面有N行,每行是一只白鼠的信息。第一个为不大于100的正整数,表示白鼠的重量;
第二个为字符串,表示白鼠的帽子颜色,字符串长度不超过10个字符。

注意:白鼠的重量各不相同。
输出
每个案例按照白鼠的重量从大到小的顺序输出白鼠的帽子颜色。
样例输入
3
30 red
50 blue
40 green
样例输出
blue
green
red

分析:模拟一下就好了,处理方式无非就是建一个结构体,输入完以后利用sort排序,自己写一个排序的规则函数就好了。

代码如下:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
typedef struct{
    int num;
    char s[10];
}Node;
bool cmp(Node a,Node b){
    return a.num>b.num;
}
int main(){
    int n;
    while(~scanf("%d",&n)){
        Node *node=new Node[n];
        for(int i=0;i<n;i++)scanf("%d %s",&node[i].num,&node[i].s);
        sort(node,node+n,cmp);
        for(int i=0;i<n;i++)printf("%s\n",node[i].s);
    }
}

J——放苹果

题目描述
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
(用K表示)5,1,1和1,5,1 是同一种分法。
输入
每行均包含二个整数M和N,以空格分开。1<=M,N<=10。
输出
对输入的每组数据M和N,用一行输出相应的K。
样例输入
7 3
样例输出
8

分析:这题我看到就是一个提前打表,打表可以有两种思想:一种是递归,一种是动态规划。
首先需要自己多举例子找规律或者多尝试一下动态规划的一些思考方式:
首先需要明确的是,无论是递归的退出条件或是动态规划的基础条件,都需要满足这以下几点:
①当0个物品要放入n个盘子的时候,这时候必然是没有任何方案。
②当1个物品要放入n个盘子的时候,很明显只有一种方案(1 0 0 0…和0 1 0 0…等等都是一样的方案)。
③当任意m个物品要放入1个盘子的时候,很明显也只有一种方案即将这m个物品放入这一个盘子就好了。
④假设i个物品要放入j个盘子里面,考虑这些情况:1.如果盘子数量比物品数量都要多,实际上这个方案就相当于i个物品放入i个盘子里面然后加j-i个空盘子,因此方案数就等于把i个物品放入i个盘子里面;2.如果是较为一般的情况,即盘子数量会比物品数量少,则可以利用动态规划的思想,思考为:i个物品放入j-1个盘子里,这时候就相当于是方案里面多加了一个空盘子,可以直接递归下去找到退出条件①②或③。除了这些方案,还有一些方案是,不会有空盘子(从递归的角度分析),必然是已经有j个物品放入j个盘子里,那么剩下i-j个物品放入j个盘子的方案数就是了。

递归代码如下:

#include<bits/stdc++.h>
using namespace std;
int f[15][15];
int fun(int m,int n){
    if(n==0)return 0;
    else if(m==0||n==1)return 1;
    else if(m<n)return fun(m,m);
    else return fun(m-n,n)+fun(m,n-1);
}
void solve(){
    for(int i=1;i<=10;i++)
        for(int j=1;j<=10;j++)
            f[i][j]=fun(i,j);
}
int main(){
    int m,n;
    solve();
    while(~scanf("%d%d",&m,&n)){
        printf("%d\n",f[m][n]);
    }
}

动态规划代码如下:

#include<bits/stdc++.h>
using namespace std;
int f[15][15];
void solve(){
    for(int i=0;i<=10;i++)
        for(int j=0;j<=10;j++)
            if(j==0)f[i][j]=0;
            else if(i==0||j==1)f[i][j]=1;
            else if(i<j)f[i][j]=f[i][i];
            else f[i][j]=f[i][j-1]+f[i-j][j];
}
int main(){
    int m,n;
    solve();
    while(~scanf("%d%d",&m,&n)){
        printf("%d\n",f[m][n]);
    }
}

K——游船出租

题目描述
现有公园游船租赁处请你编写一个租船管理系统。
当游客租船时,管理员输入船号并按下S键,系统开始计时;
当游客还船时,管理员输入船号并按下E键,系统结束计时。
船号为不超过100的正整数。当管理员将0作为船号输入时,
表示一天租船工作结束,系统应输出当天的游客租船次数和平均租船时间。
注意:由于线路偶尔会有故障,可能出现不完整的纪录,即只有租船没有还船,
或者只有还船没有租船的纪录,系统应能自动忽略这种无效纪录。
[注意]:每天的船只互不影响,比如第一天租了船1没有归还,第二天船1应该按照没有借处理。
输入
测试输入包含若干测试用例,每个测试用例为一整天的租船纪录,格式为:
船号(1~100) 键值(S或E) 发生时间(小时:分钟)
每一天的记录保证按时间递增的顺序给出。当读到船号为-1时,全部输入结束,相应的结果不要输出。
输出
对每个测试用例输出1行,即当天的游客租船次数和平均租船时间(以分钟为单位的精确到个位的整数时间,向上取整)。
样例输入
1 S 08:10
2 S 08:35
1 E 10:00
2 E 13:16
0 S 17:00
0 S 17:00
3 E 08:10
1 S 08:20
2 S 09:00
1 E 09:20
0 E 17:00
-1
样例输出
2 196
0 0
1 60

分析:这题要足够仔细仔细,要会分析如何忽略掉那些不该处理的船:
①构造结构体,来判断第i个船是否被借和是否归还以及借还的时间。
②如果只是看样例,借了以后标志一下,如果没还就不计数。或者直接就是还的记录,在这之前根本没有借的标志,这些记录都不会记录。但是如果是这样的特殊情况呢:借了以后还了,标志都打上。再平白加一个借的记录,这时候还的记录还在,没有省略就会出错。或者是重复的借同一艘船。这里我们就要巧用时间了。借船的时候需要满足之前的一次还的记录在之前一次借船时间之前,还船的时候需要满足之前一次借的记录在还的记录之后。以此实现覆盖。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define Swap(a,b){int temp=a;a=b;b=temp;}
#define INF 0x3f3f3f3f
typedef struct{
    int S_h,S_m,E_h,E_m,S,E;
}Node;
Node node[105];
int fun(int S_h,int S_m,int E_h,int E_m){
    if(E_m>=S_m)return (E_h-S_h)*60+(E_m-S_m);
    else{
        E_m+=60,E_h--;
        return (E_h-S_h)*60+(E_m-S_m);
    }
}
int main(){
    char s;
    int id,h,m,time=0,num=0;
    memset(node,0,sizeof(node));
    while(~scanf("%d",&id)){
        if(id==-1)break;
        scanf(" %c %d:%d",&s,&h,&m);
        if(id==0){
            if(num){
                int x=ceil((1.0*time)/num);
                printf("%d %d\n",num,x);
            }
            else printf("0 0\n");
            time=0,num=0;
            memset(node,0,sizeof(node));
        }
        if(s=='S'&&(node[id].S_h*60+node[id].S_m)<=(node[id].E_h*60+node[id].E_m))
            node[id].S_h=h,node[id].S_m=m,node[id].S=1;
        else if(s=='E'&&node[id].S&&(node[id].S_h*60+node[id].S_m)>=(node[id].E_h*60+node[id].E_m)){
            node[id].E_h=h,node[id].E_m=m,node[id].E=1;
            time+=fun(node[id].S_h,node[id].S_m,node[id].E_h,node[id].E_m);
            num++;
        }
    }
}

L——数字交换

题目描述
输入一个数n,然后输入n个数值各不相同,调换数组中最大和最小的两个数,然后输出。
输入
测试数据有多组,输入n(1<=n<=20),接着输入n个数。
输出
对于每组输入,输出交换后的结果。
样例输入
2
1 3
样例输出
3 1

分析:在输入的时候就找到最大最小值的下标然后交换就好了,利用宏定义来定义一个交换函数的效率会比STL的更高。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define Swap(a,b){int temp=a;a=b;b=temp;}
#define INF 0x3f3f3f3f
int main(){
    int n,pos1,pos2;
    while(~scanf("%d",&n)){
        int max=-1*INF,min=INF;
        int *num=new int[n+1];
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
            if(num[i]>max)max=num[i],pos1=i;
            if(num[i]<min)min=num[i],pos2=i;
        }
        Swap(num[pos1],num[pos2]);
        for(int i=1;i<=n;i++)
            printf("%d%c",num[i],i==n?'\n':' ');
    }
}

M——搬水果(待补题)

题目描述
在一个果园里,小明已经将所有的水果打了下来,并按水果的不同种类分成了若干堆,小明决定把所有的水果合成一堆。
每一次合并,小明可以把两堆水果合并到一起,消耗的体力等于两堆水果的重量之和。
当然经过 n‐1 次合并之后,就变成一堆了。小明在合并水果时总共消耗的体力等于每次合并所耗体力之和。
假定每个水果重量都为 1,并且已知水果的种类数和每种水果的数目。
你的任务是设计出合并的次序方案,使小明耗费的体力最少,并输出这个最小的体力耗费值。
例如有 3 种水果,数目依次为 1,2,9。可以先将 1,2 堆合并,新堆数目为3,耗费体力为 3。
然后将新堆与原先的第三堆合并得到新的堆,耗费体力为 12。
所以小明总共耗费体力=3+12=15,可以证明 15 为最小的体力耗费值。
输入
每组数据输入包括两行,第一行是一个整数 n(1<=n<=10000),表示水果的种类数。
第二行包含 n 个整数,用空格分隔,第 i 个整数(1<=ai<=1000)是第 i 种水果的数目。
输出
对于每组输入,输出一个整数并换行,这个值也就是最小的体力耗费值。
输入数据保证这个值小于 2^31。
样例输入 Copy
3
9 1 2
0
样例输出 Copy
15

N——打牌(待补题)

题目描述
牌只有1到9,手里拿着已经排好序的牌a,对方出牌b,用程序判断手中牌是否能够压过对方出牌。
规则:出牌牌型有5种。
[1] 一张 如4 则5…9可压过
[2] 两张 如44 则55,66,77,…,99可压过
[3] 三张 如444 规则如[2]
[4] 四张 如4444 规则如[2]
[5] 五张 牌型只有12345 23456 34567 45678 56789五个,后面的比前面的均大。
输入
输入有多组数据。
每组输入两个字符串(字符串大小不超过100)a,b。
a字符串代表手中牌,b字符串代表出的牌。
输出
压过输出YES 否则NO。
样例输入 Copy
12233445566677
33
样例输出 Copy
YES

O——三角阵(待补题)

把3个相同的小三角形按如下方式连接起来就形成了一个一级三角阵。
2022年寒假ACM练习2(待补题)
我们把位于顶端的小三角形标记为T,位于左端的小三角形标记为L,位于右端的小三角形标记为R。 把3个一级三角阵按同样的方式连接起来就形成了一个二级三角阵。
2022年寒假ACM练习2(待补题)
我们为顶端的三角阵的标记添加前缀T,为左端的三角阵的标记添加前缀L,为右端的三角阵的标记添加前缀R。 把3个二级三角阵按同样的方式连接起来就形成了一个三级三角阵。
2022年寒假ACM练习2(待补题)
同样地为顶端的三角阵的标记添加前缀T,为左端的三角阵的标记添加前缀L,为右端的三角阵的标记添加前缀R。 依次类推,可以构建一个N级三角阵。 如果两个小三角形有公共点,则认为这两个小三角形相邻,可以一步到达。 你的任务是求从一个小三角形走到另一个小三角形至少需要多少步。

输入
第一行是三角阵的等级N(N≤30)。
第二行和第三行都是一个长度为N的字符串,由大写字母“L”、“R”、“T”组成,表示两个小三角形的标号。
输出
输出 1 个数,表示从一个小三角形走到另一个小三角形所需的最少步数。
样例输入 Copy
3
TRL
RLR
样例输出 Copy
5
提示
从“TRL”出发,途经“TRR”、“RTT”、“RTL”、“RLT”,最后到达“RLR”,一共需要5步。

P——星象仪(待补题)

题目描述
在寂寞的夜里,星象仪是非常浪漫的东西。但是,你作为一个精神稍微有点不太正常的Geek,把原本正常的星象仪改造得像电报发送器一样。当然,你这个的构造还要更加奇葩一点。具体来说,你的星象仪是一棵满二叉树,二叉树的节点都是有两个输入端和一个输出端的AND 门或者OR 门。它们输入和输出的信号都是只是0 或者1。它们会接受子节点的输出信号,然后将这两个信号进行AND 运算或者OR 运算作为自己的输出。然后,根节点的输出信号就是整个星象仪的输出信号。叶节点的输入信号是由你来调整的,如果二叉树有K 层,那么你显然有2K个输入信号可以调整。调整一次当然只能改变一个输入信号。根据你的设定,在一开始所有的输入端的输入信号都是0。现在你希望用星象仪得到一串信号,为此,你需要不停地调整输入。
2022年寒假ACM练习2(待补题)
假定你想要用上图中的星象仪得到输出信号000111,一种可行的方案是0001→0011→1100→1111→1010→0101,但是这样你要调整14 次输入信号。更加方便的方式是0000→0000→0000→0101→0101→0101,这样你总计只需要调整2次输入信号。 由于调整输入信号是一件非常麻烦的事情,现在你希望知道对于一台给定的星象仪,如果想要得到一串给定的信号,至少需要调整多少次输入。

输入

输入文件包含多组测试数据。第一行有一个整数T,表示测试数据的组数。
每组测试数据的第一行是一个正整数 N,表示输入信号的数目。保证N 是2 的整数次幂。
第二行含有一个由 0 和1 组成的字符串S,表示你想要得到的信号。
第三行包含 N – 1 个整数,按照层次遍历顺序给出满二叉树的每个节点。整数只会是0或者1。0 表示二叉树的这个位置是一个OR 门,1 表示是一个AND 门。(T≤100,N≤8192,S的长度在10000 之内)

输出
对于每组测试数据,在单独的一行内输出结果。
样例输入 Copy
2
4
010101
0 0 0
4
111111
1 1 1
样例输出 Copy
5
4

Q——网络入侵(待补题)

题目描述
在人气动漫《某科学的超电磁炮S》第七话中,Level 5的超能力者Railgun(御坂美琴)得知了学园都市的“量产型能力者计划”,决定通过破坏研究所来阻止这个计划。为了在破坏研究所时不被监控装置发现,Railgun需要先关掉学园都市的部分监控装置。
学园都市的信息网络共有N个节点,这些节点用正整数1…N编号,它们之间通过N-1条地下光缆连接,保证任意两个节点间都是连通的。每条光缆上有一个监控装置,初始时有些监控装置是开着的,有些则是关闭的。 Railgun现在正在电话亭入侵学园都市的网络,她可以按照如下的方式操作监控装置:选择两个不同的网络节点a,b,将节点a到节点b的路径上的监控装置状态都取反(开着的装置关掉、关闭的装置打开)。注意这里的路径是指节点a,b间不经过重复节点的那一条唯一路径。
有些监控装置必须关掉后,才能保证Railgun不被发现,她希望经过若干次操作后这些装置处于关闭状态。你的任务就是计算最少需要多少次操作达到目的。

输入
输入共N+2行,第一行包含一个正整数N
第二行包含一个长度为N-1的01字符串,第i个字符表示开始时第i条光缆上的监控装置是否开着,1表示开着,0表示关闭。
第三行包含一个长度为N-1的01字符串,第i个字符表示第i条光缆上的监控装置对于Railgun来说是否必须关闭,1表示必须关闭,0表示无需关闭。
下面N-1行,每行包含两个正整数a,b(1≤a,b≤N,a≠b)表示节点a和节点b间存在一条光缆。(N≤100,000)

输出
输出共一行,包含一个非负整数,表示到达Railgun的目的所需的最少操作次数
样例输入 Copy
5
1110
0111
1 2
1 3
2 4
2 5
样例输出 Copy
1
提示
2022年寒假ACM练习2(待补题)
上图中,对于Railgun来说必须关闭的监控装置被标为红色,每条道路旁边的01数字表示这条光缆上监控装置的状态。最优的方案是选择节点3和4,虚线包围的道路上的装置改变状态(全部从打开变成关闭)。

R——左右手(待补题)

题目描述
「十代目,在吗?」
「啊~,Reborn布置的数学题,完全不知道怎么做啊!」
「没关系,交给我吧!」
Reborn 给了一个数字 X ,27 可以给 N 个数字指定值,使得这 N 个数字进行或操作以后,再乘上任意一个数字的结果等于 X, 问有多少种指定方法。
「十代目,我已经算出来了,就这样这样这样…」
聪明的 59 已经解决了问题,那你呢?
输入
第一行两个整数 X (1≤X≤109) 和 N (1≤N≤109)
输出
打印一个整数,表示所求答案(结果对1000000007取模)。
样例输入 Copy
2 2
样例输出 Copy
6
提示
有以下6种方法, 分别为 ( 第一个数字的值, 第二个数字的值, 乘数 ) :
(0, 2, 1)
(2, 2, 1)
(1, 0, 2)
(0, 1, 2)
(1, 1, 2)

上一篇:DNS的各种记录类型的应用解析


下一篇:Spring-03-DI依赖注入