JNday4-am

T1

对于T1,一直没什么思路,然而就放弃了,这道题真的挺简单的,
我们可以到着想,那么就是将末状态变为0的操作数,这就不难了,
然后类似于计数排序的思想搞一就相当于利用一个桶就可以了。
操作时,将费0数不断减1,将0变为当前0的个数/2下取整。这貌似
是一个非常优秀的贪心

T2
暴力加边,判断1和n的父亲是否相同,如果相同,answer ++,并且
暴力再次将所有的点的父亲置为自己,这样竟然有80分,可见数据之水
正解:
暴力加边,每次进行bfs
还可以单向并查集(第一次听说)

T3
贪心貌似0分,
刚开始以为是贪心,每次只砍最小的奇数,如果没有奇数,那么放弃这一刀
一定是最优的做法(4,4)(错的??)
正解是dp
f[i][j] 表示血量为i的兵,空了j刀,这里貌似并没有听懂
GG,类似于一个背包问题,可以用一个栈来维护

 

T1 集合

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <vector> 
using namespace std; const int MAXN = 5e6 + 60, MX = 1e6; int N, a[MAXN], cnt[MAXN], res, lim; int main() { freopen("multiset.in", "r", stdin); freopen("multiset.out", "w", stdout); scanf("%d", &N); for (int i = 1; i <= N; ++i) { scanf("%d", &a[i]); lim = max(lim, a[i]); ++cnt[a[i]]; } int l = 0, z = cnt[0]; for (int i = 1; i <= lim; ++i) { ++res; z = (z + 1) / 2; z += cnt[i]; } for (; z > 1; z = (z + 1) / 2) ++res; printf("%d\n", res); return 0; }

T2道路分组

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int N=500010;
typedef long long ll;

int n, m;
int vis[N], u[N], v[N];
vector<int> vec[N];

bool dfs(int u)
{
    if (vis[u]) return false;
    if (u == n) return true;
    vis[u] = 1;
    bool ret = false;
    for (int i = 0; i < vec[u].size(); i++)
    {
        ret = dfs(vec[u][i]);
        if (ret) return true;
    }
    return false;
}
        
int read()
{
    char ch = getchar();
    int x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) {x = x*10+(ch-'0');ch=getchar();}
    return x;
}

bool check(int sta, int las)
{
    for (int i = sta; i <= las; i++)
        vec[u[i]].push_back(v[i]);

    bool ret = dfs(1);

    for (int i = sta; i <= las; i++)
    {
        vis[u[i]] = vis[v[i]] = 0;
        vec[u[i]].clear();
    }
    vis[1] = 0;
    return ret;
}
    


int main()
{
    freopen("road.in","r",stdin);
    freopen("road.out","w",stdout);
    n = read(), m = read();
    for (int i = 0; i < m; i++)
    {
        //scanf("%d%d", &u[i], &v[i]);
        u[i] = read(); v[i] = read();
    }
    int now = 0, ans = 0;
    while (now < m)
    {
        int i;
        for (i = 1; i + now <= m; i <<= 1)
            if (check(now, now + i - 1)) break;
        i >>= 1; 
        int nowtmp = now + i;
        for (; i > 0; i >>= 1)
            if (nowtmp + i <= m && !check(now, nowtmp + i - 1))
                nowtmp += i;
        ans++;
        now = nowtmp;
        
    }
    cout << ans << endl;
}
            
            

T3补刀

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

const int MAXN = 1000 + 10;
int a[MAXN];
int cnt[MAXN], sta[MAXN], c[MAXN];
int f[MAXN][MAXN];

int main()
{
  freopen("cs.in", "r", stdin);
  freopen("cs.out", "w", stdout);
    int T;
    scanf("%d", &T);
    for (int num = 1; num <= T; ++num)
    {
        int N, maxn = 0;
        scanf("%d", &N);
        memset(cnt, 0, sizeof(cnt));
        memset(c, 0, sizeof(c));
        memset(f, 0, sizeof(f));
        for (int i = 1; i <= N; ++i)
        {
            scanf("%d", &a[i]); ++cnt[a[i]];
            maxn = max(maxn, a[i]);
        }
        int top = 0;
        for (int i = 1; i <= maxn; ++i)
            if (cnt[i] == 0) sta[++top] = i; else
            {
                while (cnt[i] > 1 && top > 0) {c[sta[top--]] = i; --cnt[i];}
                c[i] = i;
            }
        
        int ans = 0;
        for (int i = 1; i <= maxn; ++i)
            for (int j = 0; j <= i; ++j)
            {
                if (j > 0) f[i][j] = f[i - 1][j - 1];
                if (c[i] != 0 && j + c[i] - i < i)
                    f[i][j] = max(f[i][j], f[i - 1][j + c[i] - i] + 1);
                ans = max(ans, f[i][j]);
            }
        printf("%d\n", ans);
    }
    return 0;
}

 

posted @ 2017-10-31 21:41  ioioioioioio  阅读(160)  评论(0编辑  收藏  举报