NOIP模拟题 2016.11.5 [贪心] [坐标离散化] [循环序列LIS]

T1:
题意:大天使之剑。。有平A、重击、群击三种攻击方式,伤害分别是1、2、1。,要让所有的小兵GG,问最少需要受多少伤害。

由于群击在人数大于等于3的时候占优势,那么这种情况优先考虑群击,小于等于2的时候重击,但是如果最小的兵只有1滴HP,就群击。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
typedef long long LL;
const int maxn = 100005;
int a[maxn];
int n,m;
int main()
{
    freopen("zhijian.in","r",stdin);
    freopen("zhijian.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",a+i);
    sort(a+1,a+n+1);
    LL ans = 0;
    int cnt = n;
    int cur = 1;
    while(true)
    {
        if(!m || cur>n || !cnt) break;
        if(!a[cur]) { cur++; continue; }
        if(cnt>=3)
        {
            int delta = min(a[cur],m);
            int new_dead = 0;
            for(int j=cur;j<=n;j++)
            {
                a[j] -= delta;
                if(!a[j]) new_dead++;
            }
            ans += delta*cnt - new_dead;
            m -= delta; cnt -= new_dead;
        }
        else
            if(a[cur] == 1)
            {
                int new_dead = 0;
                for(int j=cur;j<=n;j++)
                {
                    a[j]--;
                    if(!a[j]) new_dead++;
                    else break;
                }
                ans += cnt - new_dead;
                m--; cnt -= new_dead;
            }
            else
            {
                int hit = a[cur]>>1; smin(hit,m);
                a[cur] -= (hit<<1);
                m -= hit;
                ans += cnt*hit - (!a[cur]);
                cnt -= (!a[cur]);
            }
    }
    if(cnt)
        for(int i=1;i<=n;i++) if(a[i])
            ans += (LL)a[i]*cnt - 1 , cnt--;
    printf(AUTO,ans);
    return 0;
}

T2:
Floodfill只不过数据很大,要用坐标离散化。
如果采用横向闭区间纵向开区间的方法,可能导致恰好在端点的两个小块漏算,因为横向闭区间可能没有纵向的线段来分割最后一个格子。
所以采用重复计算的方法,都记成闭区间就好了。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
#define Xn Xn
#define Yn Yn
typedef long long LL;
const int maxn = 2005;
struct Node
{
    int x1,y1,x2,y2;
}node[maxn];
int X[maxn],Y[maxn];
int Xn,Yn;
inline void discrete(int a[],int &n)
{
    sort(a+1,a+n+1);
    n = unique(a+1,a+n+1) - a - 1;
}
int vis[maxn][maxn]; // 2 for protected , 1 for occupied
void init()
{
    int M;
    scanf("%d",&M);
    int curx = 0, cury = 0;
    for(int i=1;i<=M;i++)
    {
        char ch = (char) getchar();
        while(!isalpha(ch)) ch = (char) getchar();
        int d;
        scanf("%d",&d);
        if(ch == 'U')
        {
            node[i].x2 = curx+1; node[i].y2 = cury+1;
            X[++Xn] = curx+1; Y[++Yn] = cury+1;
            curx -= d;
            node[i].x1 = curx; node[i].y1 = cury;
            X[++Xn] = curx; Y[++Yn] = cury;
        }
        else if(ch=='D')
        {
            node[i].x1 = curx; node[i].y1 = cury;
            X[++Xn] = curx; Y[++Yn] = cury;
            curx += d;
            node[i].x2 = curx+1; node[i].y2 = cury+1;
            X[++Xn] = curx+1; Y[++Yn] = cury+1;
        }
        else if(ch=='L')
        {
            node[i].x2 = curx+1; node[i].y2 = cury+1;
            X[++Xn] = curx+1; Y[++Yn] = cury+1;
            cury -= d;
            node[i].x1 = curx; node[i].y1 = cury;
            X[++Xn] = curx; Y[++Yn] = cury;
        }
        else
        {
            node[i].x1 = curx; node[i].y1 = cury;
            X[++Xn] = curx; Y[++Yn] = cury;
            cury += d;
            node[i].x2 = curx+1; node[i].y2 = cury+1;
            X[++Xn] = curx+1; Y[++Yn] = cury+1;
        }
    }
    discrete(X,Xn); discrete(Y,Yn);
    for(int i=1;i<=M;i++)
    {
        node[i].x1 = lower_bound(X+1,X+Xn+1,node[i].x1) - X;
        node[i].y1 = lower_bound(Y+1,Y+Yn+1,node[i].y1) - Y;
        node[i].x2 = lower_bound(X+1,X+Xn+1,node[i].x2) - X;
        node[i].y2 = lower_bound(Y+1,Y+Yn+1,node[i].y2) - Y;
        for(int x = node[i].x1;x < node[i].x2;x++)
            for(int y = node[i].y1;y < node[i].y2;y++)
                vis[x][y] = 2; // protected
    }
}
const int dx[] = {-1,0,0,1};
const int dy[] = {0,-1,1,0};
inline bool inRange(int x,int y) { return 0<=x&&x<=Xn && 0<=y&&y<=Yn; }
void dfs(int x,int y)
{
    vis[x][y] = 1; // occupied
    for(int k=0;k<4;k++)
    {
        int xx = x + dx[k];
        int yy = y + dy[k];
        if(!inRange(xx,yy) || vis[xx][yy]) continue;
        dfs(xx,yy);
    }
}
LL work()
{
    LL ans = 0;
    for(int x=0;x<=Xn;x++)
        for(int y=0;y<=Yn;y++)
            if(vis[x][y] ^ 1) ans += (LL)(X[x+1]-X[x]) * (Y[y+1]-Y[y]);
    return ans;
}
int main()
{
    freopen("luobo.in","r",stdin);
    freopen("luobo.out","w",stdout);
    init();
    dfs(0,0);
    LL ans = work();
    printf(AUTO,ans);
    return 0;
}

T3:
题意:每个地鼠出现有限次数t,循环出现,问LIS长度。

用链表循环,每次一个点如果没有更新d[]说明这个点以后都没有用了,delete

数据保证了n*MAX<=2e7,那么总时间复杂度不会超过这个值。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
#define smax(x,tmp) x=max((x),(tmp))
#define smin(x,tmp) x=min((x),(tmp))
#define maxx(x1,x2,x3) max(max(x1,x2),x3)
#define minn(x1,x2,x3) min(min(x1,x2),x3)
template <class T> inline void read(T &x)
{
    x = 0;
    T flag = 1;
    char ch = (char)getchar();
    while(ch<'0' || ch>'9')
    {
        if(ch == '-') flag = -1;
        ch = (char)getchar();
    }
    while(ch>='0' && ch<='9')
    {
        x = (x<<1) + (x<<3) + ch - '0';
        ch = (char)getchar();
    }
    x *= flag;
}
const int INF=0x3f3f3f3f;
const int maxn = 100005;
int n,N,t,T,cas,MAX;
struct Node
{
    int pre,suf;
    int val;
}node[maxn];
#define pre(x) node[x].pre
#define suf(x) node[x].suf
#define val(x) node[x].val
int _begin;
inline void init()
{
    n = N; t = T;
    memset(node,0,sizeof(node));
    for(int i=1;i<=n;i++)
    {
        read(val(i));
        pre(i) = i-1;
        suf(i) = i+1;
    }
    _begin=n+1;
    pre(1) = _begin; suf(n) = _begin;
    suf(_begin) = 1; pre(_begin) = n;
}
inline void erase(int root)
{
    suf(pre(root)) = suf(root);
    pre(suf(root)) = pre(root);
}
vector <int> d;
int dynamic()
{
    d.clear();
    int root = suf(_begin);
    while(true)
    {
        if(root == _begin) root=suf(root),t--;
        if(!t || root==_begin) break;
        vector <int> ::iterator it = lower_bound(d.begin(),d.end(),val(root));
        if(it == d.end()) d.push_back(val(root));
        else
        {
            if((*it) == val(root)) erase(root);
            else (*it) = val(root);
        }
        root = suf(root);
    }
    return d.size();
}
int main()
{
    freopen("dishu.in","r",stdin);
    freopen("dishu.out","w",stdout);
    scanf("%d%d%d%d",&cas,&N,&MAX,&T);
    while(cas--)
    {
        init();
        int ans = dynamic();
        printf("%d\n",ans);
    }
    return 0;
}
原创文章 152 获赞 15 访问量 6万+

猜你喜欢

转载自blog.csdn.net/ourfutr2330/article/details/53046200