四校联考2017.8.20T1填算式

由于T2和T3都太高深了太巧妙了,于是只会做T1,拿了95分。现提供95分做法与满分做法

数据范围:n≤13,1≤ai≤9,0≤k≤109

大意:给n个数,在其中填+?×,允许多个数合并为一个。求使得最终结果等于k的算式数量。(这不就是我们平常玩的24点的加强版吗?)

95分解法:我们注意到对于第一个数字,其前面的操作只能为加法,对于之后的每一个数字,我们都有四种操作:在前面填加号,减号,乘号;与前面的数字合并。注意到n的值很小,于是考虑深搜。用两个数组分别记这个算式的符号和数字,当深搜到最后的时候check。深搜部分复杂度约为O(4n-1×n)。因此最后一个点会T。

95分代码如下:

 1 include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cctype>
 7 using namespace std;
 8 int n,k;
 9 long long x,ans=0;
10 int a[30];
11 long long ex[30],opr[30];
12 struct node{
13     long long opr,num;
14 }sta[30];
15 long long check(int tot){
16     int top=0;
17     long long sum=0;
18     for(int i=1;i<=tot;++i){
19         if(opr[i]!=3){
20             sta[++top].num=ex[i];
21             sta[top].opr=opr[i];
22         }
23         else  sta[top].num*=ex[i];
24     }
25     while(top>0){
26         if(sta[top].opr==1)  sum+=sta[top].num;
27         else  sum-=sta[top].num;
28         top--;
29     }
30     return sum;
31 }
32 void tryy(int i,int j){
33     if(i>n){
34         long long now=check(j);
35         if(now==k)  ans++;
36         return ;
37     }
38     ex[j]=ex[j]*10+a[i];
39     tryy(i+1,j);
40     ex[j]/=10;
41     ex[j+1]=a[i];opr[j+1]=1;
42     tryy(i+1,j+1);
43     opr[j+1]=2;
44     tryy(i+1,j+1);
45     opr[j+1]=3;
46     tryy(i+1,j+1);
47 }
48 int main(){
49     freopen("expr.in","r",stdin);
50     freopen("expr.out","w",stdout);
51     scanf("%d%d",&n,&k);
52     int i,j;
53     for(i=1;i<=n;++i){
54         scanf("%d",&a[i]);
55     }
56     ex[1]=a[1];opr[1]=1;
57     tryy(2,1);
58     printf("%d\n",ans);
59     return 0;
60 }

满分做法:我们注意到复杂度为O(4n-1)完全可以过。因此我们只需要优化check部分即可。

我们考虑到这些算式中只有乘法具有优先级,一旦乘号后面出现加减号,这部分结果就对后面的运算不产生影响。因此我们在DFS的参数里面存储当前运算结果,一边DFS一边计算。记三个变量a,b,c。其中a代表的是当前加法算式的值,b代表的是当前这个数要乘上的倍数,c代表的是当前这一个数。初始 a=c=0,b=1。不填,则 c=10*c+x[i]。填+,则 a=a+b*c,b=1,c=x[i]。填-,则 a=a+b*c,b=-1,c=x[i]。填×,则 b=b*c,c=x[i]。最后 a+b*c就是运算结果。这样的话复杂度为O(4n-1)。可得100分。

满分代码如下:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cctype>
 7 #define ll long long
 8 using namespace std;
 9 int n,k;
10 long long ans=0;
11 ll x[30];
12 long long ex[30],opr[30];
13 void tryy(int i,ll a,ll b,ll c){
14     if(i>n){
15         if(a+b*c==k)  ans++;
16         return ;
17     }
18     tryy(i+1,a,b,c*10+x[i]);
19     tryy(i+1,a+b*c,1,x[i]);
20     tryy(i+1,a+b*c,-1,x[i]);
21     tryy(i+1,a,b*c,x[i]);
22 }
23 int main(){
24     freopen("expr.in","r",stdin);
25     freopen("expr.out","w",stdout);
26     scanf("%d%d",&n,&k);
27     int i,j;
28     for(i=1;i<=n;++i){
29         scanf("%d",&x[i]);
30     }
31     tryy(2,0,1,x[1]);
32     printf("%d\n",ans);
33     return 0;
34 }
时间: 2024-11-08 19:00:54

四校联考2017.8.20T1填算式的相关文章

10.29 FJ四校联考

//四校联考Rank 16 感觉很滋磁 (虽然考的时候抱怨厦门一中出的数学题很NOIP///) 圈地 [问题描述] n根长度不一定相同的木棍,至多可以对其中一根切一刀,然后用其中的任意根围一个三角形,求三角形的最大面积.设面积为S,输出16*S^2对998244353取模后的答案.特别地,无解输出-1. 注:退化的三角形(面积为零)不被认为是三角形,答案应该为-1. [输入文件] 输入文件为tri.in. 输入文件第一行包含两个正整数n和998244353. 第二行包含n个正整数,表示每根木棍的

20170820四校联考

来看看IOIAu巨神zzx的名言 不用循环输入就会狗啊哥哥! 上题目: T1: 填算式(expr) [题目描述] 填算式是一种简单的数学游戏,可以形式化描述如下:n 个数字a1; a2; -- ; an 排成一排(1<= ai<=9),相邻两个数字之间有一个空格.你可以在每个空格内填入运算符+- * 之一,也可以不填,要求得到的算式的运算结果等于k.你的任务是计算有多少种不同的正确算式.比如n = 3,3 个数字为2; 2; 2,k = 24时,有两种不同的正确算式:22 + 2 = 24,2

2016年9月25日四校联考

·前言:啊f**k今天早上体检,但是并不影响做题2333因为题目真的好 NOIP 啊 啊对了附中评测姬好坑啊正解强行T 23333 第一题<萝卜种子> 简要题意:小姑娘看了看狐狸的萝卜田,发现田里最多只能生长7个萝卜(多余的种子不会发芽),且4种萝卜发芽的概率是完全相同的.它们的效果分别是: 普通萝卜:生产2kg兔粮 超能萝卜:生产2kg兔粮,每种植一个其他萝卜额外产生1kg兔粮 固氮萝卜:不能用于生产兔粮,但能使每个普通萝卜和超能萝卜生产的兔粮+1kg 金坷垃萝卜:不能用于生产兔粮,但能使每

2017-3-5四校联考

szy学长出的,除了T3外都比较水 360/400. T1.小猪划船 题目大意:六只猪要过河,三只大猪ABC,三只小猪abc,其中ABCa会划船,共一只船,每次可以载2个人,给出四只猪的划船耗时,每次运载花的时间是船上耗时最小的猪的耗时乘上船上猪的个数,小猪与其对应大猪不在一起时不能与其他大猪在一起,求所有猪到对岸的最小耗时. 思路:状态最多2^7(每只猪还有船的位置),随便建图最短路或者直接搜索或者构造都能通过该题.我写的O(2^21). #include<cstdio> #include&

四校联考 推冰块

2<=n,m<=10^9,0<=k<=50000. 我们发现有用的格子不是很多,经过详细的分类讨论,只有这些格子是有用的: 四个角,以及障碍物(或减速带)本身和上下左右四个方向,以及障碍物所在行列(及±1的)的头尾两个. 那么我们只要把所有 障碍 和 减速带 按x-y和y-x排序一下,对于每一个有用的格子二分一下找到往左和往右会推到哪里,连边完暴力bfs即可. #include <iostream> #include <stdio.h> #include &

20170814四校联考

啊啊啊啊啊啊NOIAu大神ysy出题虐菜出人命啦!爆tan(pi/4)啦!被害者家属情绪稳定. ysy大佬谁敢D啊,NOIAu1st了,只适合D人了. 还是IOIAu的大佬体谅人,我还那么蒟蒻呢~ 闲话不说,上题目: T1: 宝石(gem) [题目描述]有 n 座城市,编号为 1~n,第 i 座城市里宝石的交易价格为 ai.当你经过第 i 座城市时,你可以以 ai 的价格购买或卖出一个宝石.在任意时刻,你最多只能携带一个宝石.有 m 次操作,操作分为两种:(1) 给定l,r,询问依次经过编号为l

2017-2-26福建四校联考

哎我好菜啊 从来没打过表的萌新这次想打个表结果打太多了长度超限了(后来发现根本没必要打表) ---------我是分割线 A.矩形 给定一个2*n的矩形,每个位置有一个正权值,你要把它恰好分成m个矩形,使得所有矩形的和的最大值最小并求出最小的最大值. n<=100000 m<=100 题解: 首先很显然m只是一个附加条件,如果你能分<m段,那么你一定能分m段. 看到最大值最小,最小值最大的问题,很自然想到二分答案. 然后我们用一个dp来check.用f[i]表示前i*2的矩形至少要分几段

四校联考——20170730模拟赛

今天3题都很丧. 我只会T1,所以我很弱 T1要有桶排序,不然会T,被卡常 做法就是先排序,然后前缀和乱搞 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long #pragma o1 using namespace std; inline int read(){ int x=0;char c=getchar();bool t

【四校联考】点

[题目描述] 有n个点,初始时没有边.有m个操作,操作分为两种: (1) 在i和j之间增加一条无向边,保证1<=i,j<=n. (2) 删去最后添加的k条边,保证k<=当前边数. 你想要知道最多能选取多少个两两不连通的点,以及选取的方案数.在每次操作后输出这两个值.方案数对998244353取模. [输入数据] 第一行两个整数n,m.接下来m行每行第一个数表示操作类型,接下来2或1个数表示i,j或k. [输出数据] 对于每个操作,输出一行两个整数,用一个空格隔开. [样例输入] 3 7