https://blog.csdn.net/qq_42887171/article/details/95619073 火炬手
https://blog.csdn.net/qq_42887171/article/details/95625219 雕塑
前言
有了昨天的教训,晚上再也不敢熬夜了,乖乖的早睡晚起(也就7:00起而已)今天精神倍儿棒<( ̄︶ ̄)>
今天的题终于又回到了正常水平,昨天的题差点没把我吓死(°o°;) (到现在还没改出来)
T1(电影票)
赛时:一看就有规律,立马疯狂暴力找规律,发现 也没想那么多,直接打(结果只能到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.