今天是10班在一起的最后一天,但还是要在机房度过,哎...整个人都不好了,terrible...

所以今天根本不想做题,特别又全都是数学题...

testA想过dp,写的时候各种问题,一怒之下就打了个表...不过我还是很良心的,因为电脑太渣,只打了60kb...→_→50分,比某个打了6000kb+的人还多...

然后我一直再想testB,手算了几个数据,想dp来着,最后跪了...特判有30...

testC最大的困难就在于,看!不!懂!题!啊!啊!啊!啊!啊!啊!啊!啊!啊!

 -----------------------------------------------------------------------------

testA

输入文件: testA.in  输出文件 :testA.out 时限:2000ms

 

问题描述:

如果一个数化为一个二进制数之后(没有前导0),0的个数>=1的个数。那么这个数就是方数。

Eg.(12)10 = (1100)2  2个1和2个0 所以12是一个方数。

     (6)10=(110)       2个1和1个0所以6不是一个方数。

现在方老师想知道区间[L,R]里有多少个方数。

 

输入描述:

一共一行L和R。(1<=L<=R<=2*10^9)

 

输出描述:

一个数表示[L,R]里有多少个方数。 

数据范围 N<=200 , W<=100000 , M<=19900

 

样例输入:

2 12

 

样例输出:

6

 

题解:

比dp更简单简洁的方法,组合数!//还记得SmallFat机智的解释那个线性推的公式~

 1 #define NOMBRE "testA"
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 const int MAXN = 40;
 6 
 7 int L, R, p[MAXN+10], c[MAXN+10][MAXN+10];
 8 
 9 inline int Get(int x){
10     if (!x) return 0;
11     int len = 0, ret = 0, a0 = 0, a1 = 1;
12     memset(p, 0, sizeof(p));
13     while (x)
14         p[len++] = x&1, x >>= 1;
15     for (int ls=0; ls<len-1; ls++)
16         for (int z=ls; z>=0 && z>=ls-z+1; z--)
17             ret += c[ls][z];
18 
19     for (int i=len-2; i>=0; i--)
20         if (p[i]){
21             a0 = len-i-a1;
22             for (int j=i; j>=0 && a0+j>=a1+i-j; j--)
23                 ret += c[i][j];
24             a1 ++;
25         }
26     return (len-a1>=a1) ? ret+1 : ret;//check itself
27 }
28 
29 inline void init(){
30     memset(c, 0, sizeof(c));
31     for (int i=0; i<MAXN; i++)
32         c[i][i] = c[i][0] = 1;
33     for (int i=2; i<MAXN; i++)
34         for (int j=1; j<i; j++)
35             c[i][j] = c[i-1][j]+c[i-1][j-1];
36 }
37 
38 int main(){
39     freopen(NOMBRE ".in", "r", stdin);
40     freopen(NOMBRE ".out", "w", stdout);
41 
42     init();
43     scanf("%d %d", &L, &R);
44     printf("%d\n", Get(R)-Get(L-1));
45 }

 

 

 -----------------------------------------------------------------------------

 

testB

输入文件: testB.in  输出文件testB.out 时限3000ms

 

问题描述:

定义这样一个序列(a1,b1),(a2,b2),…,(ak,bk)如果这个序列是方序列的话必须满足下面两个条件:

(1)1<=a1<=b1<a2<=b2<….<ak<=bk<=n 。其中n是给定的正整数。

(2)b1-a1,b2-a2,….,bk-ak两两互不相同。

现在方老师想知道给定n的情况下有多少种不同的长度为k的方序列。

 

 

输入描述:

第一行一个数t表示有t组测试数据。(t<=2*10^5)

第二行至第t+1行每行两个数n和k。(1<=k<=1000 , 1<=n<=1000)

 

输出描述:

一共t行,每一行表示一个答案。

 

样例输入:

6
1 1
2 1
2 2
3 1
3 2
3 3

 

样例输出:

1
3
0
6
2
0

 

题解:

 因为ai-bi的值不同,所以可以看成一个背包。由于n<=1000,物品大小就是[0, 50];

然后就可以推出公式(借用一下zyj那个美丽的图)

其中dp[j][k]表示在i位,选了k个,其和为j。//dp那部分是ysy给我讲的@Mrs.General

 

 1 #define NOMBRE "testB"
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int MOD = 1000000007;
 8 const int MAXN = 1000;
 9 
10 int n, k, T;
11 long long dp[MAXN+10][MAXN+10], c[MAXN+10][MAXN+10], fac[MAXN+10];
12 
13 inline void init(){
14     memset(c, 0, sizeof(c));
15     for (register int i=0; i<=MAXN; i++)
16         c[i][i] = c[i][0] = 1;
17     for (register int i=2; i<=MAXN; i++)
18         for (register int j=1; j<i; j++)
19             c[i][j] = (c[i-1][j]+c[i-1][j-1])%MOD;
20 
21     fac[0] = 1;
22     for (int i=1; i<=MAXN; i++)
23         fac[i] = fac[i-1]*i%MOD;
24 
25     dp[0][0] = dp[0][1] = 1;
26     for (register int i=1; i<=MAXN; i++)
27         for (register int k=50; k>=1; k--)
28             for (register int s=MAXN; s>=i; s--)
29                 dp[s][k] = (dp[s-i][k-1]+dp[s][k])%MOD;
30 }
31 
32 inline int Solve(){
33     if (n<k) return 0;
34     int ret = 0;
35     long long temp;
36     for (int l=0; l<=n-k; l++)
37         temp = (long long)c[n-l][k]*dp[l][k]%MOD,
38         ret = (temp+ret)%MOD;
39     ret = (ret*fac[k])%MOD;
40     return ret;    
41 }
42 
43 int main(){
44     freopen(NOMBRE ".in", "r", stdin);
45     freopen(NOMBRE ".out", "w", stdout);
46     
47     init();
48     scanf("%d", &T);
49     while (T--)
50         scanf("%d %d", &n, &k), printf("%d\n", Solve());
51 }

 

 

 

 -----------------------------------------------------------------------------

testC

输入文件: testC.in  输出文件: testC.out 时限: 1000ms

 

问题描述:

给定一个n*m的国际象棋棋盘(左上角那个格子是黑的),方老师在第0时刻我们把所有的黑色格子全部重新涂成0号颜色,在第i个时刻方老师会把一些点(如果4个和他有恰好有一个公共顶点的格子都涂上的是i-1号颜色)重新涂成i号颜色(这种循环会无限进行下去,而且每次重新涂颜色是同时进行的)。最后问有多少个格子恰好被重新涂了x次。

 

输入描述:

一行三个数n,m,x。(1<=n,m<=5000,x<=10^9)

 

输出描述:

一个数表示有多少个格子被重新涂了x次

 

样例输入:

3 3
1

  样例输出:

4

题解:

你得看懂题之后,就没有然后了

 1 #define NOMBRE "testC"
 2 #include <cstdio>
 3 
 4 int N, M, cj, Pri;
 5 
 6 int main(){
 7     freopen(NOMBRE ".in", "r", stdin);
 8     freopen(NOMBRE ".out", "w", stdout);
 9 
10     scanf("%d %d %d", &N, &M, &cj);
11     cj --, cj <<= 1, cj ++;
12     if (N<cj || M<cj) Pri = 0;
13     else if (N==cj) Pri = (M-cj+2)/2;
14     else if (M==cj) Pri = (N-cj+2)/2;
15     else Pri = N+M-2*cj;
16     printf("%d\n", Pri);
17 }

 

Posted on 2014-07-08 16:18  cjhahaha  阅读(198)  评论(0)    收藏  举报