怠惰是贫穷的制造厂 jzoj 2017.8.18 B组

第一题

  1. 【NOIP2013模拟联考3】库特的向量(code) (Standard IO)
    Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits
    Goto ProblemSet

Description

从前在一个美好的校园里,有一只(棵)可爱的弯枝理树。她内敛而羞涩,一副弱气的样子让人一看就想好好疼爱她。仅仅在她身边,就有许多女孩子想和她BH,比如铃,库特,等等。不过,除却巫山不是云,理树的心理只有那个帅气高大的男孩子——恭介,这让女孩子们不得不终日唉声叹气,以泪洗面。不过恭介是那样强大而完美,根本没有办法击败他,她们也只好咬牙忍痛度日,以待反击之时。

终于,她们获得了一次机会。机智的库特利用弹道学、密码学、宇宙学的知识设计出了一个密室,可以让进入的人无法从内部打开出口。库特设计密码的过程很奇葩,是由两个用整数坐标表示的n 维向量导出的。神奇的是,对于这两个向量中的任意一个,无论如何将它的坐标打乱(例如(a1,a2,a3)变成(a3,a1,a2)),打乱后的数量积都不会比原来的两个向量的数量积小。而库特就把原来的两个向量的数量积作为了密码。现在她们只用把恭介引入就可以了。但是,好事多磨,由于她们的粗心大意,在测试密室的时候不小心把自己给关了进去,而且还带走了密码纸。在外面的铃只找到了库特写着两个打乱后的向量的草稿。哇呼~能不能解救这些萌妹子,就看你了。

Input

三行。第一行一个整数N,表示N 维。

第2~3 行每行N 个整数,表示打乱后的两个向量(a1,a2,a3,a4…an),(b1,b2,b3,b4…bn).

Output

如题目要求,输出库特设计的密码

Sample Input

3

1 3 -5

-2 4 1

Sample Output

-25

Data Constraint

对于50%的数据 n<=8 , |ai|,|bi|<=1000

对于100%的数据 n<=1000, |ai|,|bi|<=100000

题解:T1:
数量积:假设有两个 维向量

那么数量积为 这里写图片描述
很明显题目要求你求出最小的数量积,
那么贪心,最小乘最大即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int a[1010],b[1010];
long long ans=0;
bool come(int a,int b)
{
    return a>b;
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]);
    sort(a+1,a+n+1);
    sort(b+1,b+n+1,come);
    for(int i=1;i<=n;i++)
    {
        ans+=a[i]*b[i];
    }
    cout<<ans;
    return 0;
}

第二题

  1. 【NOIP2013模拟联考3】恭介的法则(rule) (Standard IO)
    Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits
    Goto ProblemSet

Description

终于,在众亲们的奋斗下,最终boss 恭介被关进了库特设计的密室。正当她们松了一口气时,这个世界却发生了天翻覆地的变化:地面开始下沉,天空开始变成血红色,海水沸腾……一幅世界末日的图景。美鱼从她手中的古籍《若山牧水诗歌集》中发现了原因:白鸟は かなしからずや 空の青 海のあをにも 染まずただよふ 。大(xia)意(shuo)就是狡猾的恭介在创造这个世界的时候就篡改了法则。而这个法则的起源,就是一只生死之间的猫。这个猫被关在一个黑盒子里,盒子里有两个毒气罐,如果有任意一个毒气罐被打开那么猫将会被杀死,法则也能得到纠正。然而外界能控制的仅仅是这两个毒气罐被打开的概率。假设第一个毒气罐被打开的概率为1/x,第二个毒气罐为1/y(x,y 为正整数),那么当两个概率和为1/(n!)时,猫将会被莫名其妙地杀死。现在美鱼想知道,有多少对(x,y)可以让猫被莫名其妙杀死。

Input

一行,一个正整数n

Output

一行,满足题意的(x,y)对数。

Sample Input

6

Sample Output

135

Data Constraint

对于30%的数据 n<=6

对于60%的数据 n<=50

对于100%的数据 n<=700000

题解:
这里写图片描述
设y=m+k嘛(m=n!),代入得:x=(m*m)/k+(m*k)/k,那么显然答案为(n!)的平方的因子个数;
.
.
先上30分暴力的代码

#include<iostream>
#include<cstdio>
using namespace std;
int ans=0;
long long jc[10],n;
int main()
{
    cin>>n;
    jc[0]=1;
    for(int i=1;i<=9;i++)
    jc[i]=jc[i-1]*i;
    for(double i=jc[n];i<=26000000;i++)
    {
        double u=(i*jc[n])/(i-jc[n]);
        int y=u;
        if(y==u&&y>=1) 
        {
            //cout<<i<<" "<<y<<endl;
            ans++;
        }
    }
    cout<<ans;
    return 0;
}

再来用线性筛的60分代码
.
.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
LL n=0,m=0,k=0,z[3000000],a[3000000],b[3000000];
bool p[7000001], q[7000001];
int d[1000000],e[1000000],sum[1000000],ss=1;
LL ans=1;
void xs()
{
    m=0;
    for(int i=2;i<=n;i++)
    {
        if(!p[i])
        {
            z[++m]=i;
        }
        for(int j=1;j<=m;j++)
        {
            if(i*z[j]>n) break;
            p[i*z[j]]=true;
        }
    }
    for(int i=1;i<=m;i++) q[z[i]]=true;
}
void get(int x)
{
    if(q[x])
    {
        k++;
        a[k]=1;
        b[x]=k;
        return ;
    }
    else 
    {
        while(x>1)
        {
            if(q[x])
            {
                a[b[k]]++;  
                return ;
            }
            else 
            {
                for(int j=1;j<=m;j++)
                {
                    if(z[j]>x) break;
                    while(x%z[j]==0)
                    {
                        a[b[z[j]]]++;
                        x=x/z[j];
                    }
                }
            }
        }
    }
}
void js(int i)
{
    memset(d,0,sizeof(d));
    int dl=0,x=0;
    memcpy(e,sum,sizeof(e));
    memset(sum,0,sizeof(sum));
    while(a[i]!=0)
    {
        d[++dl]=a[i]%10;
        a[i]/=10;
    }
    int u;
    for(int j=1;j<=dl;j++)
    {
        u=x;
        x=0;
        d[j]*=2;
        x=d[j]/10;
        d[j]=d[j]%10;
        d[j]+=u;
    }
    if(x)
    {
        d[++dl]=x;
    }   
    int l=1;
    d[l]++;
    while(d[l]==10)
    {
        d[l]=0;
        d[++l]+=1;
        if(l>dl) {dl=l;break;}
    }
    for(int j=1;j<=ss;j++)
    {
         x=0;
        for(int k=1;k<=dl;k++)
        {
            sum[k+j-1]=e[j]*d[k]+x+sum[j+k-1];
            x=sum[k+j-1]/10;
            sum[j+k-1]%=10;
        }
        sum[j+dl]=x;
    }
    ss=dl+ss;
    while(sum[ss]==0&&ss>1)
    ss--;


}
int main()
{
    memset(sum,0,sizeof(sum));
    sum[1]=1;
    cin>>n;
    xs();
    k=0;
    for(int i=2;i<=n;i++)
    get(i); 
    for(int i=1;i<=k;i++)
    {
        ans*=a[i]*2+1;
        js(i);
    }
    for(int i=ss;i>=1;i--)
    cout<<sum[i];
    return 0;
}

最后是我改了很久的AC代码

.
.

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define LL long long
#define P 10000000
using namespace std;
LL n=0,m=0,k=0,z[3000000],a[3000000],b[3000000];
bool p[7000001];
LL d[1000000],e[1000000],ans[1000000],ss=1;
__attribute__((optimize("-O3")))//过程O3,不开不能AC,会WA一个点 
void xs()//筛1到n的素数 
{
    m=0;
    for(int i=2;i<=n;i++)//线性筛素数
    {
        if(!p[i])
        {
            z[++m]=i;
        }
        for(int j=1;j<=m;j++)
        {
            if(i*z[j]>n) break;
            p[i*z[j]]=true;//标记为不是质数 
        }
    }
    for(int i=1;i<=m;i++)
    {
        LL j=n;
        while(j)
        {
            a[i]+=(j/=z[i]);//每个数都可以拆成素数的幂方和 
        }
    }
    for(int i=1;i<=m;i++)
    {
        a[i]=a[i]*2+1;//因为是求n!的平方内的因子嘛 
    }
}
__attribute__((optimize("-O3")))
void js()
{
    LL  l=1,t=0;
    for(int i=1;i<=m;i++)
    {
        t=0;
        for(int j=1;j<=l;j++)
        {
            ans[j]=ans[j]*a[i]+t;
            t=ans[j]/P;//压了7位,不能压8位,会不行 
            ans[j]%=P;
        }
        if(t!=0)
        {
            l++;//算完有多的,往前拓展一位 
            anshg[l]=t;
        }
    }

    for(int i=l;i>=1;i--)
    {
        if(i!=l)
        {
            LL j=P/10;
            while(j>0&&ans[i]/j==0)//压了位,要考虑数前面有0的情况 
            {
                cout<<0;
                j/=10;
            }
        }
        cout<<ans[i];
    }
}
int main()
{
    memset(a,0,sizeof(a));
    memset(ans,0,sizeof(ans));
    ans[1]=1;
    cin>>n;
    xs();
    js();
    return 0;
}

ps:AC代码是我看了纪中集训坐我前面的学姐的博客才改好的,毕竟今天第一次写线性筛素数,改进了一下线性筛

学姐博客传送门:http://blog.csdn.net/ssl_lyy/article/details/77387886

第三题

  1. 【NOIP2013模拟联考3】沙耶的玩偶(doll) (Standard IO)
    Time Limits: 1000 ms Memory Limits: 131072 KB Detailed Limits
    Goto ProblemSet

Description

在美鱼和理树后援团拯救世界的同时,外表柔弱的理树也开始坚强起来,思考着离开这个世界的办法。误打误撞地,她遇上了正在教室破坏课桌打开迷宫入口的沙耶。沙耶告诉理树,这个世界的出口就是这个迷宫的出口。于是理树毫不犹豫地跟沙耶一起跳进了迷宫。在迷宫里,两个女孩子互帮互助,一会儿割绳子,一会儿泡温泉,一会儿雕冰块,跌跌撞撞地走到了终点。不出所料,终点也有一个机关在等着她们。

终点的机关是一个立着的m*n 的方格棋盘,在有些格子上放了一个玩偶,而有些地方直接挖了个大坑。只有取走所有玩偶才能打开出口。但是,由于奇怪的设定,理树和沙耶不能直接触碰玩偶,他们需要操纵机器人来收集它。机器人的走法很奇怪,和国际象棋的马有点像,只不过马可以走任意方向的1*2 路线,它们只会由上往下走r*c(或c*r)的路线,不能回头。而机器人一旦经过一个有玩偶的格子,那个格子上的玩偶将被回收,并且在机器人离开时,那个格子会变成一个坑。理树可以把机器人放在任何一个有玩偶的格子上作为起点,也可以在任何一个有玩偶的格子回收机器人。机器人行走可以视为瞬移,只不过每一次设置新起点都会消耗1 时间。并且,有坑的格子不能落脚。

就在这个紧要关头,玩偶狂热爱好者的沙耶却流着口水智商归0。理树不得不转而求助你,帮忙计算出最少多少时间就能收集到所有玩偶。

Input

第一行包含4 个整数M、N、R、C,意义见问题描述。接下来M 行每行一个长度为N 的

字符串。如果某个字符是’.’,表示这个地方有一个玩偶;如果这个字符是’x’,表示这个地

方是坑。

Output

输出一个整数,表示最短时间。

Sample Input

3 3 1 2

.x.

Sample Output

4

Data Constraint

30%的数据中,1<=M,N<=4,1<=R,C<=3。

70%的数据中,1<=M<=20,1<=N<=4,1<=R,C<=3。

100%的数据中,1<=M,N<=50,1<=R,C<=10。

Hint这里写图片描述

题解:由于我还没写,先贴一下官方的题解

先观察题目要求,如果当前机器人在格子(X,Y),即第 X 行第 Y 列,那么它能到
达的地方最多四个:(X+R,Y+C),(X+R,Y-C),(X+C,Y+R),(X+C,Y-R)。当然,
其中某些格子可能是不能到达的或者超越了边界。
用一个简单的迭代深度优先搜索解决。迭代需要总时间数,然后让每个机器人通
过深搜的形式遍历棋盘,然后判断棋盘是否已经被全部覆盖。由于 M、N、R、C
都很小,所以效果不错。加上适当的剪枝,或许可以多过一点测试数据。(30 分)
考虑到 M 很大,N 却很小。因此想到状态压缩。也可以发现 R、C 也很小,因此
状态压缩应该可行。
观察每一行,这一行上的格子最多只能由它上面 Max{R,C}行的格子跳过来,而
在再上去就跟它无关了。于是可以状态压缩这 N*Max(R,C)规模的矩阵,用 01 串
表示这个格子当前是否存在机器人,然后将其压缩成一个数存储起来。
对于新的一行,上面的空格子必须全部放机器人,所以一定是由上面 Max(R,C)
行中的一些格子跳过来。但是是由哪些格子跳过来的呢?这些格子由分别跳向哪
些格子?这个无法得知。不过,可以想到上面 Max(R,C)中选出来的格子和当前
新一行中的空格子一定是一一对应的。于是想到二分图匹配的方法,让新一行中
所有空格子与上面 Max(R,C)行中的可以跳过来的格子做最大匹配。求出最大匹
配后,把那些匹配上了的格子清除机器人,并在新的一行中建立机器人。
如果最大匹配<新一行中空格子个数,那么必须新建一些机器人来保证覆盖全
图,这个答案加到动态规划的答案中。
总复杂度为 ( 2 )
* ( , ) 2 O M N
N Max R C
。(70 分)
上面的状态压缩动态规划中已经提到了二分图匹配的思想,所以 100%数据的方
法也呼之而出。
求整个图要多少机器人路径才能覆盖,就是求整个图的最小路径覆盖。而且观察
此题是有向无环图,所以可以使用二分图最大匹配的方法。
左边建立 M*N 个点,右边建立 M*N 个点。如果(X,Y)可以跳向(X’,Y’),那么就
让左边的(X,Y)向右边的(X’,Y’)连一条边。
建好图后,做一次最大匹配。那么最终答案就是空格子个数-最大匹配数。
总复杂度为 ( )
2 2 O M N 。(100 分)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值