NOIP模拟题 2015.8.10 T2
NOIP模拟题 2015.8.10 T3

NOIP模拟题 2015.8.9 T3

HJWJBSR posted @ 2015年8月17日 15:19 in 题解 , 479 阅读

这是破神蒯的一个sxbk的原题,在一个叫做Bayan的比赛的2014年shortcutB题

题面:有n个白球的和m个黑球,要求将他们排成一列使得每对异色球之间的人数之和最小,并求方案数模10^9+7。

n,m<=100w,T组数据,T<=100

输入格式:第一行一个T,然后T行每行两个n和m

输出格式:T行每行两个答案

Sample Input:

4
3 1
4 1
3 2
4 2
 
Sample Output:
1 2
2 1
4 1
8 4

题解:做这套题睡了2h+,所以考的比较hehe,当然就算再给我2h+我也不一定做得出这个题。

这道题喜闻乐见的要推式子:

定义Sn代表n个人两两颜色相异的时候的答案,通过计算可得Sn=(n3-3*n2+2n)/6

先设n>=m,然后将考虑将m个黑球插进来,定义Ai代表第i个黑球插到了第Ai个白球的的后面,我们假设Ai单调不减

简单容斥可得:ans=Sn+m-Sn-Sm-所有的黑球对所有的白球对的贡献-所有的白球对所有的黑球对的贡献,

倒数第二个东西就是Σi=1 to m Ai*(n-Ai)

最后一个东西就是Σi=1 to m-1 Σj=i+1 to m Aj-Ai-1,然后这东西明显是可以拆出来的

最后两个东西相加得到:Σi=1 to m (n-2*i-m-1)2-[Ai-(n+2*i-m-1)/2]2

这东西系数是负的,所以后面那个和平方要最小。

所以我们分类讨论当n-m为奇数,Ai后面那个东西总是能取到0,因为(n+2*i-m-1)/2总是大于等于1,小于等于n-1。这样的话就可以直接算了,并且方案数是1

当n-m为偶数的时候,后面那个和平方最优取值应该是0.25,此时Ai有两个最优取值,并且由于i每次增大1,所以Ai取较大的那个,而Ai-1取较小的那个的时候也不会违反假设。所以答案还是可以直接算,然后方案数是2m,这个快速幂一下就好了

为了能过我们还要优化一下,前面那个m个常数的和平方是可以化简的,化简成:(3n2m-3m3-3m)/12

然后还有第一问是要用long double,输出用long long,后面的要取模。然后就没了

en窝不会LaTeX所以这些东西都看起来很丑请不要介意(好吧其实也没人看吧)

然后其实代码也很丑,这虽然是一般设定不过还是说一下好了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define ll long long
#define M 1000000007
long double ans;ll t,n,m;
inline int Read()
 {
 	int x=0;char y;
 	do y=getchar(); while (y<'0'||y>'9');
 	do x=x*10+y-'0',y=getchar(); while (y>='0'&&y<='9');
 	return x;
 }
ll Quick_Power(ll x,int y)
 {
 	ll z=1;
 	while (y)
 	 {
 	 	if (y&1) z=z*x%M;
 	 	y >>= 1;
 	 	x=x*x%M;
 	 }
 	return z;
 }
inline long double Calc(ll x)
 {return (x*x*x-3*x*x+2*x)/6;}
inline long double calc()
 {long double x=n,y=m;return (3*x*x*y+y*y*y-y)/12;}
inline void Solve1()
 {printf("%lld 1\n",(ll)(ans+0.5));}
inline void Solve2()
 {
 	ans+=0.25*m;
 	printf("%lld %lld\n",(ll)(ans+0.5),Quick_Power(2,m));
 }
int main()
 {
 	freopen("love.in","r",stdin);freopen("love.out","w",stdout);
 	t=Read();
 	while (t--)
 	 {
 	 	n=Read();m=Read();
 	 	if (n<m) swap(n,m);
 	 	ans=Calc(n+m)-Calc(n)-Calc(m);
 	 	ans-=calc();
 	 	if ((n-m)&1) Solve1();else Solve2();
 	 }
 	return 0;
 }

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter