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 + 22 = 24。

【输入格式】
从文件expr.in 中读入数据。
输入的第一行包含两个整数n; k,表示数字个数和要求的答案。
接下来一行,包含n 个整数,第i 个数为ai。相邻两个整数用一个空格隔开。
【输出格式】
输出到文件expr.out 中。
输出一个整数,表示不同的正确算式个数。
【样例1 输入】
4 11
1 2 3 4
【样例1 输出】
3
【样例1 解释】
3 个正确的算式为:12 + 3 ?? 4 = 11,1 + 2 3 + 4 = 11,1 ?? 2 + 3 4 = 11。
【样例2 输入】
7 1
1 1 1 1 1 1 1
【样例2 输出】
241

【样例3 输入】
10 3276
7 7 8 6 1 4 1 1 1 4
【样例3 输出】
104

【子任务】
子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只
解决一部分测试数据。
每个测试点的数据规模及特点如下表:



题解:

比较简单的搜索吧(虽然我打挂了)
直接DFS从左到右枚举每个空格填+,-,×还是不填,然后计算这个式子的值,这样复杂度是4^(n-1)*n,期望得分95分

在DFS的参数里面存储当前运算结果,可以一边DFS一边计算,具体做法如下:
维护参数 a,b,c,初始 a=c=0,b=1
不填,则 c->10c+x[i]
填+,则 a->a+bc,b=1,c=x[i]
填-,则 a->a+bc,b=-1,c=x[i]
填×,则 b->bc,c=x[i]
最后 a+bc就是运算结果
复杂度优化到4^(n-1),期望得分100分

部分分算法:
如果不会DFS,可以用三重循环通过测试点1~12,期望得分60分

如果不会循环,可以用条件语句通过测试点1~4或者1~8,期望得分20~40分

代码:

#include<cstdio>
#define r register
#define Fn "expr"
typedef long long ll;
int n,k,ans,x[15];
bool check(ll a,ll b,ll c){return a+b*c==k;}
void dfs(int st,ll a,ll b,ll c){
    if(st==n){ans+=check(a,b,c);return;}
    dfs(st+1,a,b,c*10+x[st]);
    dfs(st+1,a+b*c,1,x[st]);
    dfs(st+1,a+b*c,-1,x[st]);
    dfs(st+1,a,b*c,x[st]);
}
int main(){
    freopen(Fn".in","r",stdin);
    freopen(Fn".out","w",stdout);
    scanf("%d%d",&n,&k);
    for(r int i=0;i<n;i++)scanf("%d",x+i);
    dfs(1,0,1,x[0]);
    printf("%d\n",ans);
    return 0;
}



T2:

闭合子图(closure)

【样例1 输入】
5 5
1 3
3 4
5 4
1 5
2 1
【样例1 输出】
5



题解:

部分分算法:枚举子集
枚举 V 的非空子集 S,根据定义判定是否满足条件,更新答案
判定部分实现优秀的话可以做到O(1),期望得分20~25分

部分分算法:枚举区间
注意到点集构成的区间只有 n(n+1)/2 个,可以枚举区间然后将区间内的点作为S,进行判定
直接实现的复杂度 O(n^2*m),期望得分35分

注意到对于一个点u的出边(u,v),只有最小的v和最大的v是有用的,可以将m缩小到2n
复杂度 O(n^3),期望得分40分

进一步地,可以枚举左端点,然后从小到大枚举右端点,维护区间内出边指向点的最小值和最大值
复杂度 O(n^2),期望得分50分

部分分算法:树的数据

对于测试点11,12,显然所有形如[1,i]的区间都满足条件
所以答案为n,复杂度O(n),期望得分10分,结合上述算法期望得分60分

部分分算法:DAG的数据

对于测试点13,14,判定区间[l,r]是否满足要求只需要[l,r]内的点指向的点编号均不超过r
用p[i]表示i指向的点的编号(不存在则p[i]=i),则可以枚举r,找出第一个满足p[i]>r的i,那么l=i+1,i+2,...,r都是合法的,答案加上r-i
从左到右维护p[i]的递减单调栈即可,复杂度O(n),期望得分15分。
结合上述算法期望得分75分

算法:分治

考虑分治,假设当前统计的是[L,R]有多少个子区间合法,取mid=[(L+R)/2],统计包含mid和mid+1的合法区间个数
记p[i],q[i]分别表示i的出边指向点的最小值和最大值(不存在则为i)
则区间[l,r]合法的条件是
对于l<=i<=mid,p[i]>=l (1) 且 q[i]<=r (2)
对于mid<i<=r,p[i]>=l (3) 且 q[i]<=r (4)
条件(1)只和l有关,条件(4)只和r有关,做一遍前缀/后缀最值把合法的l,r处理出来即可
记Q[l]=max{q[i]|l<=i<=mid},条件(2)就是r>=Q[l]
如果记r‘为最小的r>=mid满足p[r‘]<l,那么条件(3)就是r<r‘,且r‘随l的减小而增大
那么只需从大到小枚举l,维护Q[l],单调维护r‘,答案加上[Q[l],r‘)内的合法r个数,这一部分复杂度是线性的
总复杂度O(nlogn),期望得分100分
如果复杂度不小心多写了一个log可能只有95分

代码:

#include<cstdio>
#define maxn 300010
#define reg register
#define Fn "closure"
#define mod 1000000007
#define mid (lt+rt>>1)
typedef long long ll;
int n,m,ans;
int l[maxn],r[maxn],s[maxn];
inline int read(){
    reg int x=0,f=1;reg char c=getchar();
    for(;c<‘0‘||c>‘9‘;f=c==‘-‘?-1:1,c=getchar());
    for(;c>=‘0‘&&c<=‘9‘;x=(x<<3)+(x<<1)+c-‘0‘,c=getchar());
    return x*f;
}
void bs(int lt,int rt){
    if(rt-lt==1){ans+=l[lt]==lt&&r[lt]==lt;return;}
    reg int mr=0;
    s[mid-1]=0;
    for(reg int i=mid;i<rt;i++){
        if(r[i]>mr)mr=r[i];
        s[i]=s[i-1]+(mr==i);
    }
    reg int ml=1<<30,pos=mr=mid;
    for(reg int i=mid;i-->lt;){
        if(l[i]<ml)ml=l[i];
        if(r[i]>mr)mr=r[i];
        while(pos<rt&&l[pos]>=i)pos++;
        if(ml==i&&pos>mr)(ans+=s[pos-1]-s[mr-1])%=mod;
    }
    bs(lt,mid);
    bs(mid,rt);
}
int main(){
    freopen(Fn".in","r",stdin);
    freopen(Fn".out","w",stdout);
    n=read();m=read();
    for(reg int i=1;i<=n;)l[i]=r[i]=i++;
    while(m--){
        reg int s=read(),t=read();
        if(t<l[s])l[s]=t;
        if(t>r[s])r[s]=t;
    }
    bs(1,n+1);
    printf("%d\n",ans);
    return 0;
}



由于时间原因,T3暂时没有打,请大佬们谅解!

时间: 2024-10-24 22:42:02

20170820四校联考的相关文章

10.29 FJ四校联考

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

四校联考2017.8.20T1填算式

由于T2和T3都太高深了太巧妙了,于是只会做T1,拿了95分.现提供95分做法与满分做法 数据范围:n≤13,1≤ai≤9,0≤k≤109 大意:给n个数,在其中填+?×,允许多个数合并为一个.求使得最终结果等于k的算式数量.(这不就是我们平常玩的24点的加强版吗?) 95分解法:我们注意到对于第一个数字,其前面的操作只能为加法,对于之后的每一个数字,我们都有四种操作:在前面填加号,减号,乘号:与前面的数字合并.注意到n的值很小,于是考虑深搜.用两个数组分别记这个算式的符号和数字,当深搜到最后的

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