jzoj 2019.7.12【NOIP2012模拟10.26】比赛总结

38 篇文章 0 订阅
6 篇文章 0 订阅

https://blog.csdn.net/qq_42887171/article/details/95619073 火炬手

https://blog.csdn.net/qq_42887171/article/details/95625219 雕塑

前言

有了昨天的教训,晚上再也不敢熬夜了,乖乖的早睡晚起(也就7:00起而已)今天精神倍儿棒<( ̄︶ ̄)>

今天的题终于又回到了正常水平,昨天的题差点没把我吓死(°o°;)  (到现在还没改出来)

T1(电影票

赛时:一看就有规律,立马疯狂暴力找规律,发现   f_{i,j} = f_{i-1,j} + f_{i,j-1}  也没想那么多,直接打(结果只能到35)

我以为漏了模数,好吧,是我多想了,这题就是让我们打高精度的。(还不是普通的,还有除法、压位)

我jio得吧,先打完二三题的暴力再来打高精度,结果打完暴力溜回来,居然调不出来(果然还是太蒟蒻了

11:27 我要赶紧调了

11:28 来不及了,赶快呀

11:29 MD,再没调出来,劳资砸了这电脑凸(艹皿艹 )

11:29:50 算了,弃疗...( _ _)ノ|壁

11:30  然后。。。就没有然后了。。。

正解:

假设将买《变形金刚3》票的人记为s 。买《哈利波特7》的人记为x 

,则n个买《变形金刚3》的与m个买《哈利波特7》的人的队伍就可以用一个具有n个s和m个x的字符串,显然这样的字符串共有C(n+m,n)个,

其中不满足问题要求的串一定存在一个最靠左的位置p,使得从第一个字符到第p个字符为止的子串中x的个数比s的个数大1.

如sxsxx就是一个不满足条件的串,其中p=5。

我们将从头到p为止的子串中的字符s换成x则得到一个具有n+1个s,m-1个x的串,可以证明这种转换是一一对应的,即任意一个n+1个s,m-1个x的串都可以按照逆规则转换成一个不满足题目条件的串,

转换规则为在任意一个n+1个s,m-1个x中找到最靠左的p,使得从头到p的子串中s的个数比x个数大1,将到p为止的子串中的s与x互换则得到n个s和m个x的串,且此串一定不能满足条件,而具有n+1个s,m-1个x的串只有C(n+m,n+1)。

那么ans=C(n+m,n)-C(n+m,n+1)=(n+1-m)*(m+n)!/(m!*(n+1)!)种方案可满足条件。

由于问题的规模很大,结果远远超出longint,要用高精度算法,(呵呵,别调萎了)

虽然结果表达式中有分母,但实际结果一定是整数,所以不需要除法运算,

具体运算时只要求出(n+1-m)*(m+n)!/(m!*(n+1)!的质因子分解式,然后做高精度即可,而任意一个质因子r在n!中出现次数为[n/r]+[n/(r^2)]+[n/(r^3)]+...[n/(r^k)],[]为取整。

(摘自jzoj题解)

CODE

const
        mo=1000000000;
var
        ans:array[0..10000000]of int64;
        n,m,sum,k:int64;
        i,j:longint;
procedure jc(k:longint);
var
        sum:int64;
        i:longint;
begin
        for i:=1 to ans[0] do begin
                ans[i]:=ans[i]*k+sum;
                sum:=ans[i] div mo;
                ans[i]:=ans[i] mod mo;
        end;
        while (sum<>0) do begin
        	inc(ans[0]);
		ans[ans[0]]:=sum;
                sum:=sum div mo;
	end;
end;
procedure chu(k:longint);
var
        i:longint;
begin
        for i:=ans[0] downto 1 do begin
        	ans[i-1]:=ans[i-1]+ans[i] mod k*mo;
                ans[i]:=ans[i] div k;
	end;
        while (ans[ans[0]]=0) do dec(ans[0]);
end;
begin
        readln(n,m);
        ans[0]:=1;ans[1]:=1;
        for i:=n+2 to n+m do jc(i);
        jc(n+1-m);
        for i:=1 to m do chu(i);
        write(ans[ans[0]]);
        for i:=ans[0]-1 downto 1 do begin
                k:=ans[i];
                sum:=0;
	        while (k>0) do begin
                        inc(sum);
                        k:=k div 10;
                end;
                for j:=1 to 9-sum do write('0');
                write(ans[i]);
        end;
end.

T2(火炬手

赛时:

妈呀!!!这道题一看就很难的样子,于是就打了个暴力交了(当然也有T1的原因)

我枚举 m 当 ans 是01串时就OK了

正解:

水法:暴力枚举,不过枚举的是答案ans(如果我再想会儿,是不可以AC了?-_-?)

           用DFS或BFS枚举ans,递归 ans*10 和 ans*10+1 的情况,只要 mod n=0,就输出ans div n。

正经解法(俗称正解):

如果从m出发来求的话就不好做了,我们可以从n*m出发来做,实际上我们只关心对n的余数,而一个数(x1x2...xn)对n的余数可以通过(x1x2x3...xn-1)对n的余数得到,关系式为:

                              (x1x2...xn)mod n =(10*(x1x2..xn-1)mod n+xn)mod n ;

题目又要求最小的,所以可以用bfs来做,

用bfs[i,1]表示当前选0还是1,bfs[i, 2]表示当前的余数,bfs[i,3]表是父结点。

复杂度O(N)

CODE

var
        n,k,ans:qword;
function min(a,b:qword):qword;
begin
        if a<b then exit(a) else exit(b);
end;
procedure dfs(t:qword);
begin
        if t<k then begin
                if t mod n=0 then begin
                        ans:=min(ans,t div n);
                        exit;
                end;
                dfs(t*10);
                dfs(t*10+1);
        end;
end;
begin
        k:=111111111111111111;
        ans:=k;
        readln(n);
        dfs(1);
        if ans<>k then write(ans)
        else write('no solution');
end.

 T3(雕塑

赛时:看到题,这不就是N皇后吗?又gou得有哪里不对劲,于是打了个暴力就交了

正解:状压DP/容斥原理(以下介绍的是容斥原理)

看到数据范围n<=20,m<=10,方案种数<=2^63-1。

由于方案总数较大,若采用单纯的搜索算法,很难做到不超时。

其实观察一下数据规模中的n和m,m<=10,这是一条重要的信息,m比n*n少得多,那么雕塑“安置在禁区内的方案数”就必然比“安置在禁区外的”方案数少得多,

"安置在禁区内的雕塑仍可以用dfs,但是必须搞清一个问题:安置在禁区内的方案总数与求不在禁区的方案数又有什么关系呢,这就恰好就是容斥原理中淘汰原则的十分巧妙的运用。

再来进行进一步的分析:用rk表示把k个雕塑放在了n*n的方格上,并且这k个雕塑都处在禁区放置位置上的方案数,根据容斥原理的推论n个雕塑都安置在非禁区内的方案数等于

n!-r1*(n-1)!+r2*(n-2)-r3*(n-3)!...(-1)^k*rk*(n-k)!...+(-1)^n*rn

(摘自jzoj题解)

CODE(本蒟蒻用的是容斥)

var
        h,l,pow,r:array[0..1000]of int64;
        a:array[0..100,0..5]of int64;
        i,j,n,m:longint;
        ans:int64;
procedure dfs(x,y,p:longint);
var
        i:longint;
begin
        if y=0 then begin
                inc(r[p]);
                exit;
        end
        else begin
                for i:=x+1 to m do begin
                        if (h[a[i,1]]=0)and(l[a[i,2]]=0) then begin
		                h[a[i,1]]:=1;
                                l[a[i,2]]:=1;
		                dfs(i,y-1,p);
                                h[a[i,1]]:=0;
                                l[a[i,2]]:=0;
                        end;
                end;
        end;
end;
begin
        readln(n,m);
        for i:=1 to m do read(a[i,1],a[i,2]);
        for i:=1 to m do dfs(0,i,i);
	ans:=1;
	pow[0]:=1;pow[1]:=1;
        for i:=2 to n do begin
                pow[i]:=pow[i-1]*i;
                ans:=ans*i;
        end;
	for i:=1 to m do
	        if odd(i) then
                        ans:=ans-r[i]*pow[n-i]
	        else
                        ans:=ans+r[i]*pow[n-i];
        writeln(ans);
end.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值