POJ杂题题解

POJ1147

根据最后一列,可以确定答案中0/1的个数,同样第一列也确定了,因为每次操作之后得到的矩阵都是排过序的,不妨考虑一下把最后一列移到第一列,这样可以得到最后一列与第一列排序的对应关系,然后根据这个对应关系就可以知道每一行经过排序会发生什么变化,这样不断递推就可以求出整个矩阵了。由于只需要第一行,输出即可。

Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>

using namespace std;

#define P system("pause");
#define B printf("Break
");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000

int read()
{
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return f * x;
}
#define N 3010
int f[N],nxt[N],ans[N];
int main()
{
    int n = read(),cnt = 0;
    for(int i = 1;i <= n;++i) f[i] = read();
    int tot = 0;
    for(int i = 1;i <= n;++i)
        if(!f[i]) nxt[++tot] = i;
    for(int i = 1;i <= n;++i)
        if(f[i]) nxt[++tot] = i;
    for(int i = 1,pos = nxt[1];i <= n;++i)
    {
        printf("%d ",f[pos]);
        pos = nxt[pos];
    }
    putchar('
');
}

POJ1163

数字三角形,dp入门题。
(f_{x,y} = max (f_{x+1,y},f_{x+1,y+1}) + a_{x,y})

Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>

using namespace std;

#define P system("pause");
#define B printf("Break
");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000

int read()
{
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return f * x;
}
#define N 150
int f[N][N],a[N][N],n;
int dfs(int x,int y)
{
    if(f[x][y]) return f[x][y];
    if(x == n) return f[n][y] = a[n][y];
    else return f[x][y] = max(dfs(x + 1,y),dfs(x + 1,y + 1)) + a[x][y];
}
int main()
{
    n = read();
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= i;++j)
            a[i][j] = read();
    printf("%d
",dfs(1,1));
}

POJ1922

理性分析一下,发现这个人一定会跟着骑得最快的人一块骑,因此只需统计出最先到达终点的人的时间即可。注意在0时刻之前出发的,要么一定会被这个人超过,要么永远追不上,所以不予考虑。

Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>

using namespace std;

#define P system("pause");
#define B printf("Break
");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000

int read()
{
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return f * x;
}
int main()
{
    int n;
    while(~scanf("%d",&n) && n)
    {
        double ans = inf;
        for(int i = 1;i <= n;++i)
        {
            double v,t,dt = inf;
            scanf("%lf%lf",&v,&t);
            if(t >= 0) dt = ceil(t + 4.5 / (v / 3600.0));
            ans = min(ans,dt);
        }
        printf("%d
",(int)ans);
    }
}

POJ2211

题目大意:给定 (n), (k), 求给定排列在所有 (A_n^k) 种排列中的排名的字典序。

这个题一看就跟组合数有关系,假设得到的排列是 (x_1,x_2,...,x_k) ,考虑所有比这个排列小的,按位考虑,显然所有第一个元素比 (x_1) 小的都符合,这些排列一共有 ((x_1-1)A_{n-1}^{k-1})个。然后继续往后考虑,到第 (i) 个元素,符合条件的是 ((x_i-1)A_{n-i}^{k-i}) ,但是这里的 (x_i) 有一点变化,如果前面已经考虑过比这个 (x_i) 小的元素了,那么就需要去重,具体方法见代码。

Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>

using namespace std;

#define P system("pause");
#define B printf("Break
");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000

ll read()
{
    ll x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return f * x;
}
#define N 20
ll fac[N],x[N];
ll a(ll n,ll m)
{
    if(n < m) return 0;
    return fac[n] / fac[n - m];
}
int main()
{
    ll T = read();fac[0] = 1;
    for(ll i = 1;i <= 12;++i) fac[i] = fac[i - 1] * i;//预处理阶乘
    for(ll j = 1;j <= T;++j)
    {
        ll n = read(),k = read(),ans = 0;
        for(ll i = 1;i <= k;++i) x[i] = read();
        for(ll i = 1;i <= k;++i)
        {
            ans += (x[i] - 1) * a(n - i,k - i);//按位计算
            for(int l = i + 1;l <= k;++l)
                if(x[l] > x[i]) x[l]--;//这里去重
        }
        printf("Variace cislo %lld ma poradove cislo %lld.
",j,ans + 1);//诡异的输出格式
    }
}

POJ2215

题目大意:给定一个矩形,内部每个点有权值,多次询问一个子矩形内部权值和。

就是个水题啊,二维前缀和一下就搞定了。

Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>

using namespace std;

#define P system("pause");
#define B printf("Break
");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000

int read()
{
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return f * x;
}
#define N 1010
int a[N][N],sum[N][N];
int main()
{
    int T = read();
    while(T--)
    {
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));
        int r = read(),s = read();
        for(int i = 1;i <= r;++i)
        {
            for(int j = 1;j <= s;++j)
            {
                a[i][j] = read();
                sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];
            }
        }
        int q = read();
        while(q--)
        {
            int r1 = read(),s1 = read(),r2 = read(),s2 = read();
            int ans = sum[r2][s2] - sum[r2][s1 - 1] - sum[r1 - 1][s2] + sum[r1 - 1][s1 - 1];
            printf("Absolutni hodnota pohodlnosti je %d bodu.
",ans);
        }
        puts("");
    }
}

POJ2229

题目大意:求一个数 (n) 按照2的幂次拆分的方案数。

看到方案数,又看到数据范围 (n leq 10^6) ,那就是dp了呗。

定义 (dp_i) 为拆分数 (i) 的方案数,它可以从 (i-1,i-2,...,i-2^k) 转移过来。故方程显然:

[dp_i = sum_k^{log_2 i}dp_{i-2^k} ]

再仔细一看,这不就是完全背包的形式吗,有 (log_2n) 件物品,求装入体积为 (n) 的背包的方案总数。
(O(nlog n)) 复杂度。

还有一种打表找规律做到 (O(n)) 的方法,当 (i) 为奇数时,它只能通过 (i-1+2^0) 得到,比如:(5) 只能通过 (4+2^0) 得到,当 (i) 为偶数时,它既可以通过 (i-1+2^0) ,又可以通过 (dfrac{i}{2}*2) 得到,比如:(6) 可以通过 (5+2^0) 得到,也可以通过 (3*2) 得到。

代码是完全背包做法。

Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>

using namespace std;

#define P system("pause");
#define B printf("Break
");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000

int read()
{
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return f * x;
}
#define N 1000100
#define mod 1000000000
int dp[N],a[30];
int main()
{
    int n = read();
    int tot = 1,cnt = 0;
    while(tot <= n) a[++cnt] = tot,tot <<= 1;
    dp[0] = 1;
    for(int i = 1;i <= cnt;++i)
    {
        for(int j = a[i];j <= n;++j)
        {
            dp[j] = (dp[j] + dp[j - a[i]]) % mod;
        }
    }
    printf("%d
",dp[n]);
}

POJ2232

什么叫“随机”啊,那就是可以随便操作的意思。如果三种手势都有,我们完全可以直接操作一下让每个人都获胜,因为保证了不存在平局嘛。而如果只有两种手势,那就只能是赢的那种手势的人才能获胜。一种手势比较显然,都可以获胜。

Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>

using namespace std;

#define P system("pause");
#define B printf("Break
");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000

int read()
{
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return f * x;
}
int main()
{
    int n;
    while(scanf("%d 
",&n) != EOF)
    {
        int sums = 0,sumc = 0,sumf = 0;
        string s;
        getline(cin,s);
        for(int i = 0;i < s.size();++i)
        {
            if(s[i] == 'C') sumc++;
            if(s[i] == 'S') sums++;
            if(s[i] == 'F') sumf++;
        }
        if((sumf != 0 && sums != 0 && sumc != 0) || (sumf == n || sums == n || sumc == n))
        {
            printf("%d
",n);
            continue;
        }
        else
        {
            if(sumf == 0 && sums != 0 && sumc != 0) printf("%d
",sumc);
            else if(sumf != 0 && sums == 0 && sumc != 0) printf("%d
",sumf);
            else if(sumf != 0 && sums != 0 && sumc == 0) printf("%d
",sums);
        }
    }
}

POJ2234

Nim游戏模板题,若每堆数量异或和为0,则先手必败,否则先手必胜。

Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<set>
#include<queue>
#include<vector>
#include<string>

using namespace std;

#define P system("pause");
#define B printf("Break
");
#define A(x) cout << #x << " " << (x) << endl;
#define AA(x,y) cout << #x << " " << (x) << " " << #y << " " << (y) << endl;
#define ll long long
#define inf 1000000000
#define linf 10000000000000000

int read()
{
    int x = 0,f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return f * x;
}
int n;
int main()
{
    while(scanf("%d",&n) != EOF)
    {
        int ans = 0;
        for(int i = 1;i <= n;++i) ans ^= read();
        puts(ans ? "Yes" : "No");
    }
}

POJ2242

Code

POJ2245

Code

POJ2262

Code

POJ2301

Code

POJ2309

Code

POJ2313

Code

POJ2334

Code

POJ2346

Code

POJ2348

Code

POJ2350

Code

POJ2352

Code

POJ2381

Code

POJ2405

Code

POJ2406

Code

原文地址:https://www.cnblogs.com/lijilai-oi/p/12759295.html