【2017.10.25】noip赛前集训 | T1画方框【暴力解题】、T2买西瓜【DP】、T3蚂蚁路径【组合数 + 容斥原理】

T1画方框

【问题描述】

在前面的游戏中,由于 moreD 每次都用最优策略赢了他的宠物 CD,CD 现在很郁闷,于 是他一个人在地板上画画东西了。别人都是说,“画个圈圈诅咒你”,但是 CD 很有特点,他 喜欢“画个框框诅咒你……”。 现在我们把 CD 画的东西记录到一个 N×N 方阵上了,1 表示 CD 画过的地方,0 表示空 白,请问 CD 最多可能画了多少不重复个方框呢? 方框就是所有以 1 为边的正方形,最小的方框是一个 1,CD 画方框的时候,是完全可 能把两个不一样的方框的某些边重复画到同一个位置上的。参见样例。

【数据描述】

对于 30%的数据 N<=100。 

对于 50%的数据 N<=500。 

对于 100%的数据 N<=1000。

【题解】

大暴力,听说 n就可以AC这道题。

#include <cstdio>

const int MAXN = 1000 + 7;

int n, ans;
bool mx[MAXN][MAXN];

bool check(int x, int y, int len) {
    for (int i = x; i <= len + x - 1; i++) if (!mx[i][y] || !mx[i][y + len - 1]) return 0; 
    for (int i = y; i <= len + y - 1; i++) if (!mx[x][i] || !mx[x + len - 1][i]) return 0;
    return 1;
}

int read() {
    int x = 0;
    char ch = getchar();
    
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch <= '9' && ch >= '0') x = x * 10 + ch - 48, ch = getchar();
    
    return x;
}

int main() {    
    freopen("matrix.in", "r", stdin);
    freopen("matrix.out", "w", stdout);

    n = read();

    for (int i = 1; i <= n; i++) 
        for (int j = 1; j <= n; j++) {
            mx[i][j] = read();
        }
            
//    for (int i = 1; i <= n; i++) {
//        for (int j = 1; j <= n; j++) printf( mx[i][j] == 1 ? "1 " : "0 ");
//        printf("\n");
//    }
//        
    for (int len = 1; len <= n; len++)
        for (int i = 1; i + len - 1 <= n; i++)
            for (int j = 1; j + len - 1 <= n; j++) {
                if (!mx[i][j]) continue;
                if (check(i, j, len)) ans++;
            } 
            
    printf("%d\n", ans);
    return 0;
}
... ...

 是我没写对还是啥的,以上代码只过了3个点。

 

T2 买西瓜

【题意】

暑假大家在这里集训都很辛苦吧,买汽水怎么够呢,symbol 又准备给大家买西瓜消暑 啦,刚刚你就拼命花最多的钱,这次每天都可以吃西瓜,但你得保证花的钱最少…… 假设我们集训 N 天,第 i 天西瓜一个 Pi 元并且能吃 Di 天。每天我们最多能买一个西 瓜,要是买西瓜那天我们已经有西瓜了,如果又买一个,那么之前那个即使没吃完也得扔 掉。 在保证我们每天都能吃到西瓜的情况下,我们最少要花多少钱呢?

【数据描述】 

对于 50%的数据,n<=500; 

对于 80%的数据,n<=30000; 

对于 100%的数据,n<=50000。

【题解】

 一道DP。

设 f [ i ] 表示前 i - 1 天都有西瓜吃,第 i 天再买个西瓜(大概......)。 

那我们就得到状态转移方程 f [ i ]  =  std::min( f [ i ],  f [ j ]);

具体代码:                                团长太神了!!!!%%%%%dalao
#include <cstdio>
#include <algorithm>

const int MAXN = 5e4 + 7;

int n, w[MAXN], v[MAXN], maxn, f[MAXN];

int main() {
//  freopen("watermelon.in", "r", stdin);
//     freopen("watermelon.out", "w", stdout);

    scanf("%d", &n);
    
    for (int i = 1; i <= n; i++) f[i] = 0x7fffffff;
    
    for (int i = 1; i <= n; i++) scanf("%d", &w[i]);
    for (int j = 1; j <= n; j++) {
        scanf("%d", &v[j]);
        if (maxn < v[j]) maxn = v[j];    
    }
    
    f[1] = w[1];
    for (int i = 2; i <= n; i++) {
        for (int k = 1, j = i - k ; k <= maxn && j > 0; k++, j = i - k) {
            if (j + v[j] >= i) f[i] = std::min(f[i], f[j]);
        }
        f[i] += w[i];
    }
    
//    for (int i = 1; i <= n; i++) printf("%d ", f[i]);
    
    int ans = 0x7fffffff;
    for (int k = 0, j = n - k ; k <= maxn && j >= 0; k++, j = n - k) {
        if (j + v[j] - 1 >= n) ans = std::min(ans, f[j]);
    }                                  
    
    printf("%d\n", ans);
    return 0;
}
View Code

 

T3 蚂蚁路径

【问题描述】 

汽水和西瓜真的是人见人爱啊,Symbol 发现蚂蚁也来了,两只蚂蚁分别从两个位置出 发分别走到汽水和西瓜所在的地方: 蚂蚁 A 在坐标(0,0)的位置,B 在(p,0),A 要走到(m,n),B 要走到(m,q),其中 m,n,p,q 都 是小于 100000 的正整数,且(p < m , q < n)。蚂蚁只能沿着坐标系中整数组成的网格向 x 轴或者 y 轴的正方向爬行。请问,两只蚂蚁路径不重叠(两个路径没有相交的地方)的情 况有多少种?

【数据范围】

对于 50%的数据 m+n 小于 20。 

对于 70%的数据 m+n 小于 20000。 

对于 100%的数据 m+n 小于 200000。  

提示:20! = 2432902008176640000 < 2^63。

【题解】

组合数 + 容斥原理

 

posted @ 2018-02-15 14:21  E-Valley  阅读(213)  评论(0)    收藏  举报