[位运算] [搜索] [递推优化] [计算几何] TEST 2016.7.15

NOIP2014 提高组模拟试题

第一试试题

题目概况:


中文题目名称


合理种植


排队


科技节


源程序文件名


plant.pas/.c/.cpp


lineup.pas/.c/.cpp


scifest.pas/.c/.cpp


输入文件名


plant.in


lineup.in


scifest.in


输出文件名


plant.out


lineup.out


scifest.out


每个测试点时限


1s


1s


1s


测试点数目


10


10


10


每个测试点分值


10


10


10


内存上限


128MB


128MB


128MB

1.      合理种植

(plant.pas/.c/.cpp)

【问题描述】

大COS在氯铯石料场干了半年,受尽了劳苦,终于决定辞职。他来到表弟小cos的寒树中学,找到方克顺校长,希望寻个活干。

于是他如愿以偿接到了一个任务……

美丽寒树中学种有许多寒树。方克顺希望校园无论从什么角度看都是满眼寒树,因此他不希望有三棵甚至更多寒树种在一条直线上。现在他把校园里n棵寒树的坐标都给了大COS,让他数出存在多少多树共线情况。(若一条直线上有三棵或以上的树,则算出现一个多树共线情况。)

【输入】

输入文件名为plant.in。

第1行一个正整数n,表示寒树棵数。

接下来n行,每行两个非负整数x、y,表示一颗寒树的坐标。没有两颗寒树在同一位置。

【输出】

输出文件名为plant.out。

输出一个整数,表示存在多少多树共线情况。

【输入输出样例】


plant.in


plant.out


6

0 0

1 1

2 2

3 3

0 1

1 0


1

【数据范围】

对于30%的数据,有n≤10;

对于50%的数据,有n≤100;

对于100%的数据,有n≤1,000,0≤x,y≤10,000。

2.      排队

(lineup.pas/.c/.cpp)

【问题描述】

小sin所在的班有n名同学,正准备排成一列纵队,但他们不想按身高从矮到高排,那样太单调,太没个性。他们希望恰好有k对同学是高的在前,矮的在后,其余都是矮的在前,高的在后。如当n=5,k=3时,假设5人从矮到高分别标为1、2、3、4、5,则(1,5,2,3,4)、(2,3,1,5,4)、(3,1,4,2,5)都是可行的排法。小sin想知道总共有多少种可行排法。

【输入】

输入文件名为lineup.in。

一行两个整数n和k,意义见问题描述。

【输出】

输出文件名为lineup.out。

输出一个整数,表示可行排法数。由于结果可能很大,请输出排法数mod 1799999的值。

【输入输出样例】


lineup.in


lineup.out


5 3


15

【数据范围】

对于20%的数据,有n≤10,k≤40;

对于60%的数据,有n≤100,k≤500;

对于100%的数据,有n≤100,k≤n*(n-1)/2。

3.      科技节

(scifest.pas/.c/.cpp)

【问题描述】

一年一度的科技节即将到来。同学们报名各项活动的名单交到了方克顺校长那,结果校长一看皱了眉头:这帮学生热情竟然如此高涨,每个人都报那么多活动,还要不要认真学习了?!这样不行!……于是,校长要求减少一些活动,使每位学生只能参加一项(一名同学要参加某活动,必须已报名且该活动未被去掉)。当然,他也不希望哪位同学因此不能参加任何活动。他想知道自己的方案能否实行。

【输入】

输入文件名为scifest.in。

输入数据包括多组。

对于每组数据:

第一行两个正整数n和m,分别表示活动数和学生数。

接下来n行,每行m个为0或1的数。第i+1行第j列的数若为1,表示j同学报名参加活动i,否则表示j同学没有报名参加活动i。

【输出】

输出文件名为scifest.out。

对于每组数据输出一行,若校长方案可行则输出“Yes”,否则输出“No”。(均不包括引号)

【输入输出样例】


scifest.in


scifest.out


3 3

0 1 0

0 0 1

1 0 0

4 4

0 0 0 1

1 0 0 0

1 1 0 1

0 1 0 0


Yes

No

【数据范围】

对于20%的数据,n≤10,m≤200,数据组数≤10;

对于60%的数据,n≤16,m≤300,数据组数≤100;

对于100%的数据,n≤16,m≤300,数据组数≤1,000。

*************************************************Cut Line********************************************************

第一题

最初的O(2n2logn) 但是因为STL 的 map 卡常, T了一半

TLE代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int maxn=1005;
const double eps=1e-7;
inline int dcmp(double x)
{
    if(fabs(x) <= eps) return 0;
    return x>0.0? 1 : -1;
}
struct Line
{
    double k,b;
    Line (const double _k,const double _b) { k=_k;b=_b; }
    bool operator == (const Line l) const
    {
        return !dcmp(k - l.k)  &&  !dcmp(b - l.b);
    }
    bool operator < (const Line l) const
    {
        if(dcmp(k - l.k)==0) return b < l.b;
        return k < l.k;
    }
};
struct Point
{
    int x,y;
}point[maxn];
#define x(i) point[i].x
#define y(i) point[i].y
map <Line,int> g;
map <Line,int> ::iterator it;
int non[maxn*10];
int main()
{
    freopen("plant.in","r",stdin);
    freopen("plant.out","w",stdout);
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&point[i].x,&point[i].y);
    for(int i=1;i<n;i++)
        for(int j=i+1;j<=n;j++)
        {
            if(x(i) == x(j))
            {
                non[x(i)]++;
                continue;
            }
            double k=(double) (y(i)-y(j)) / (x(i)-x(j));
            double b=(double) y(i) - k * x(i);
            if(!g.count(Line(k,b))) g[Line(k,b)]=1;
            else g[Line(k,b)]++;
        }
    int ans=0;
    for(it=g.begin();it!=g.end();it++)
    {
        if((*it).second>=2) ans++;
    }
    for(int i=0;i<=10000;i++)
        if(non[i]>=2) ans++;
    printf("%d",ans);
    return 0;
}

某神犇想出来的方法, 枚举所有三元组, 用前面去改变后面的判断

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int maxn=1005;
struct Point
{
    int x,y;
}point[maxn];
#define x(i) point[i].x
#define y(i) point[i].y
int n;
typedef long long LL;
const LL base=(1ll<<30); // must bigger than the 1e9 ‘coz the minimum of rake is 1/(9999*10000)
LL rake[maxn][maxn];
bool a[maxn][maxn];
int main()
{
    freopen("plant.in","r",stdin) ;
    freopen("plant.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&x(i),&y(i));
    for(int i=1;i^n;i++)
        for(int j=i+1;j<=n;j++)
            rake[i][j] = x(i)==x(j)? 1ll : base * (y(i)-y(j)) / (x(i)-x(j));
    int ans=0;
    for(int i=1;i^(n-1);i++) // not strictly n^3
        for(int j=i+1;j^n;j++)
            for(int k=j+1;k<=n;k++)
                if(rake[i][j] == rake[j][k])
                    if(a[i][j] || a[j][k] || a[i][k])  a[i][j] = a[j][k] = a[i][k] = true;
                    else ans++, a[i][j] = a[j][k] = a[i][k] = true;
    printf("%d",ans);
    return 0;
}

再给个标程, 每次给个标记, 同一个斜率如果x坐标在左边则说明之前算过, 借此可以排除掉斜率相同算过的情况

标程:

#include <fstream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
ifstream fin("plant.in");
ofstream fout("plant.out");
long n;
struct xxx{long x,y;} a[1005];
struct kk{long dx,dy;bool c;} k[1005];
bool operator <(kk k1,kk k2){
    if (k1.dx==10001) return k2.dx<10001;
    if (k2.dx==10001) return 0;
    return k2.dx*k1.dy<k1.dx*k2.dy;
}
bool operator ==(kk k1,kk k2){
    if (k1.dx==10001||k2.dx==10001)
        return k1.dx==k2.dx;
    return k2.dx*k1.dy==k1.dx*k2.dy;
}
void init(){
    long i;
    fin>>n;
    for (i=0;i<n;i++)
        fin>>a[i].x>>a[i].y;
}
void tr(){
    long i,j,s,ans=0;
    bool f;
    for (i=0;i<n;i++){
        for (j=0;j<n;j++)
            if (i!=j)
                if (a[i].x==a[j].x){
                    k[j].dx=10001;
                    k[j].c=a[i].y<a[j].y;
                }else{
                    k[j].dx=a[j].x-a[i].x;
                    k[j].dy=a[j].y-a[i].y;
                    if (k[j].dx<0){
                        k[j].dx=-k[j].dx;
                        k[j].dy=-k[j].dy;
                    }
                    k[j].c=a[i].x<a[j].x;
                }
        for (j=i;j<n-1;j++) k[j]=k[j+1];
        sort(k,k+n-1);
        f=1; s=0;
        for (j=0;j<n-2;j++){
            s++;
            f=f&&k[j].c;
            if (!(k[j]==k[j+1])){
                if (f&&s>1) ans++;
                f=1; s=0;
            }
        }
        if (f&&k[n-2].c&&s>0) ans++;
    }
    fout<<ans;
}
int main(){
    init();
    tr();
    fin.close();
    fout.close();
    return 0;
}

第二题

动态规划但是可以用前缀和优化或者变换一下递推公式, 把相同部分替换掉

原来的 1AC 代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int maxn=105;
const int mod=1799999;
int n,k;
int f[maxn][maxn*maxn];
int main()
{
    freopen("lineup.in","r",stdin);
    freopen("lineup.out","w",stdout);
    scanf("%d%d",&n,&k);
    memset(f,-1,sizeof(f));
    for(int i=1;i<=n;i++) f[i][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=min(k,i*(i-1)/2);j++)
        {
            bool flag=true;
            f[i][j]=0;
            for(int p=0;p<=i-1;p++)
            {
                if(!~f[i-1][j-p]) continue;
                flag=false;
                f[i][j] += f[i-1][j-p];
                if(f[i][j]>=mod) f[i][j]%=mod;
            }
            if(flag) f[i][j]=-1;
        }
    printf("%d",f[n][k]);
    return 0;
}

第三题

位运算 + 可行性剪枝(先考虑人数多的,容易更快发现冲突)

但是使用位向量生成法的话要一块一块地跳, 所以dfs更优

TLE代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int maxn=20;
const int maxm=305;
int n,m;
struct Activity
{
    int s[11]; // max of 300 evry int has 32 bits
    int cnt;
    bool operator < (const Activity t) const
    {
        return cnt >= t.cnt;
    }
}act[maxn];
inline bool init()
{
    if(!~scanf("%d%d",&n,&m)) return false;
    memset(act,0,sizeof(act));
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j^m;j++)
        {
            int tmp;
            scanf("%d",&tmp);
            if(tmp) act[i].s[j>>5] |= (1 << (j - (j>>5<<5)) ),act[i].cnt++;
        }
    }
    sort(act+1,act+n+1);
    return true;
}
int now[11];
inline bool check()
{
    for(int j=0; j^(m-1>>5); j++)
        if(now[j]^(0xffffffff)) return false;
    if(!(m-1>>5)) return now[0] ^ ((1<<m)-1)? false : true;
    else return now[m-1>>5] ^ ((1<<m-1-(m-1>>5))-1)? false : true;
}
bool bit()
{
    for(int status=1; status<=(1<<n)-1; )
    {
        memset(now,0,sizeof(now));
        bool flag=false;
        int pos=0;
        for(int i=1;i<=n;i++)
        {
            if(!(status & (1<<i-1))) continue; // don‘t forget to check here!!
            for(int j=0;j<=(m-1>>5);j++)
                if((now[j] & act[i].s[j]) ^ 0) { flag=true;pos=i-1;break; }
                else now[j] |= act[i].s[j];
            if(flag) break;
        }
        if(flag) // step by blocks!!
        {
            status %= (1<<pos);
            status += (1<<pos-1);
        }
        else status++;
        if(!check()) continue;
        else return true;
    }
    return false;
}
int main()
{
    freopen("scifest.in","r",stdin);
    freopen("scifest.out","w",stdout);
    while(init())
        if(bit()) printf("Yes\n");
        else printf("No\n");
    return 0;
}

标程:

#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
FILE *fin=fopen("scifest.in","r"),*fout=fopen("scifest.out","w");
long n,m;
long x[20][10],h[20];
bool yes;
void init(){
    long i,j,k,c;
    memset(x,0,sizeof(x));
    for (i=0;i<n;i++){
        h[i]=k=0;
        for (j=0;j<m;j++){
            fscanf(fin,"%ld",&c);
            if (c==1){
                x[i][k/31]+=1<<(k%31);
                h[i]++;
            }
            k++;
        }
    }
    for (i=0;i<n-1;i++)
        for (j=i+1;j<n;j++)
            if (h[i]<h[j]){
                k=h[i]; h[i]=h[j]; h[j]=k;
                for (c=0;c<10;c++){
                    k=x[i][c]; x[i][c]=x[j][c]; x[j][c]=k;
                }
            }
}
void tr(long p,long sx[10],long sh){
    if (p==n){
        if (sh==m) yes=1;
        return;
    }
    long i,t[10];
    for (i=0;i<10;i++){
        if ((sx[i]&x[p][i])>0) break;
        t[i]=sx[i]|x[p][i];
    }
    if (i==10) tr(p+1,t,sh+h[p]);
    if (!yes) tr(p+1,sx,sh);
}
int main(){
    fscanf(fin,"%ld%ld",&n,&m);
    do{
        init();
        yes=0;
        tr(0,x[19],0);
        if (yes) fprintf(fout,"Yes\n");
            else fprintf(fout,"No\n");
        fscanf(fin,"%ld%ld",&n,&m);
    }while (!feof(fin));
    fclose(fin);
    fclose(fout);
    return 0;
}

时间: 2024-12-26 06:16:28

[位运算] [搜索] [递推优化] [计算几何] TEST 2016.7.15的相关文章

Codeforces 631 D. Dreamoon Likes Sequences 位运算^ 组合数 递推

https://codeforces.com/contest/1330/problem/D 给出d,m, 找到一个a数组,满足以下要求: a数组的长度为n,n≥1; 1≤a1<a2<?<an≤d: 定义一个数组b:b1=a1, ∀i>1,bi=bi−1⊕ai ,并且b1<b2<?<bn−1<bn: 求满足条件的a数组的个数并模m: 人话:求一个a数组满足递增,并且异或前缀和也递增 ,求出a数组个数mod m. 太菜了,不会,看了很多题解才会的,这里总结一下:

hdu--1978--记忆化深度搜索||递推

这题 我开始的做法是 记忆化搜索  但是tm地竟然tle了...很想不通 因为数据很小啊 就100 虽然方案的总数可能会很大.. 然后 我就去百度 记忆化搜索 看下是不是我用错方法了 事实证明 我虽然没有用错 但还是 学到了很多=-=. 其实  我很早以前 也看过关于 记忆化搜索的一些介绍 但是 并没有太多感觉 并不是那些作者写的不好 而是我的水平没到 感受不了.. 很多东西会在不知不觉中提升~ 我想 将我读的这篇介绍 传到这篇博客里来 似乎只能上传照片和视频=-=   那我给个链接吧  传送

POJ 3220 位运算+搜索

转载自:http://blog.csdn.net/lyhypacm/article/details/5813634 DES:相邻的两盏灯状态可以互换,给出初始状态.询问是否能在三步之内到达.如果能的话.输出不属.超出3步就输出more. 貌似典型应用是位压缩.我觉得各种按位运算用的也很巧妙.判断两盏灯是不是状态一样的时候,和交换状态的时候.先广搜一遍,保存到达各种状态的最短路径,然后查询就可以了. 1 #include<iostream> 2 #include<cstdio> 3

Luogu P5658 括号树|搜索+递推

CSP2019 S组D1T2 题目链接 #include<bits/stdc++.h> using namespace std; int cc,to[600000],net[600000],fr[600000],fa[600000],zhan[600000],t,n,nt[600000]; long long s[600000]; char ch[600000];string st;bool vis[600000]; void addedge(int u,int v) { cc++; to[c

位运算的另一种姿势

在蒟蒻Cydiater日常水题的过程中,忽然遇到了一道题.中间有一个过程是要求在很快的时间内求出$1500$大小的两个01串的与之后存在多少个1. 最坏的,扫一遍,整体复杂度$O(N)$,好像没有什么可以优化的空间了QAQ.我开始考虑用位运算的与操作优化,因为其有$1500$个元素,所以可以考虑把这个东西拆成$\frac{N}{32}$个01串. 但是这之后好像就又存在一个问题.如何快速的统计一个二进制的01串里有多少个1?如果不要求$O(1)$,可以不停的统计lowbit,那么这个复杂度就和有

codeforces 630C - Lucky Numbers 递推思路

630C - Lucky Numbers 题目大意: 给定数字位数,且这个数字只能由7和8组成,问有多少种组合的可能性 思路: 假设为1位,只有7和8:两位的时候,除了77,78,87,88之外还哇哦加上前面只有7和8的情况,一共是6位.所以递推式不难写出dp[i]=pow(2,i)+dp[i-1]; 代码: #include <bits/stdc++.h> using namespace std; typedef long long ll; ll ans[56]; void init ()

递归,递推,记忆化搜索,空间优化(数字三角形)

题目链接:http://poj.org/problem?id=1163 1.递归思想:第一层到最底层的最优路径可以分解为:第一层到第二层来,再加上第二层的最优路径 状态: Time Limit Exceeded #include <algorithm> #include <stdio.h> #define MAX 101 using namespace std; int maps[MAX][MAX]; int n; int Sum(int i,int j) { if(i==n) r

用矩阵乘法优化递推

(有关矩阵乘法的基本规则请自行搜索) 引例:求斐波那契数列的第 n 项 mod 1000000007 的值,n <= 1018. 分析:斐波那契数列的递推式为 f(n) = f(n-1)+f(n-2),直接循环求出 f(n) 的时间复杂度是 O(n),对于题目中的数据范围显然无法承受.很明显我们需要对数级别的算法. 由于 f(n) = 1*f(n-1) + 1*f(n-2) 这样的形式很类似于矩阵的乘法,所以我们可以先把这个问题复杂化一下,将递推求解 f(n) 与 f(n-1) 的过程看作是某两

动态规划 数字三角形(递归,递推,记忆化搜索)

题目要求: 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 在上面的数字三角形中寻找在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大.路径上的每一步都只能往左下或右下走.只需要求出这个最大和即可,不必给出具体路径. 三角形的行数大于1小于等于100,数字为 0 - 99 输入格式: 5 //三角形行数.下面是三角形 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 解题思路: 用二维数组存放数字三角形 D[r][j] //表示第i行第j个元素的