zoukankan      html  css  js  c++  java
  • Noip2007提高组

    2水题 + 1中等 + 1稍难


    t1.统计数字

    题目

    题意:给定n个数,按数字从小到大的顺序输出数字及出现次数。

    思路:[水题]爱怎么搞怎么搞,反正我就是要用优先队列。

    Code:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    using namespace std;
    //Mystery_Sky
    //
    #define INF 0x3f3f3f3f
    #define M 1000100
    #define ll long long
    inline 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*10+c-'0';c=getchar();}
    	return x*f;
    }
    int n;
    struct node{
    	int x;
    	inline bool operator <(const node& a) const{
    		return a.x < x;
    	}
    };
    priority_queue <node> Q;
    
    int main() {
    	n = read();
    	for(int i = 1; i <= n; i++) {
    		int x = read();
    		Q.push((node){x}); 
    	}
    	node last = Q.top();
    	Q.pop();
    	int count = 1;
    	while(!Q.empty()) {
    		node top = Q.top();
    		Q.pop();
    		if(top.x == last.x) count++;
    		else {
    			printf("%d %d
    ", last.x, count);
    			count = 1;
    			last = top;
    		}
    		//printf("->%d %d<-
    ", top.x, count);
    	}
    	printf("%d %d
    ", last.x, count);
    	return 0;
    }
    

    t2.字符串的展开

    题目

    题意:给定三个参数p1,p2,p3,按相应的要求展开给定的字符串。

    思路:[模拟]要你干嘛就照着做不就过了。

    Code:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    #include <string>
    using namespace std;
    //Mystery_Sky
    //
    #define INF 0x3f3f3f3f
    #define M 1000100
    #define ll long long
    inline 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*10+c-'0';c=getchar();}
    	return x*f;
    }
    int p1, p2, p3;
    string st, ans;
    int pos[M];
    
    inline void give_number(char a, char b)
    {
    	if(p1 == 3) {
    		for(int i = 1; i <= b-a-1; i++) {
    			for(int j = 1; j <= p2; j++) ans += '*';
    		}
    	}
    	else {
    		if(p3 == 1) {
    			for(char i = a+1; i < b; i++) {
    				for(int j = 1; j <= p2; j++) ans += i;
    			}
    		}
    		else {
    			for(char i = b-1; i > a; i--) {
    				for(int j = 1; j <= p2; j++) ans += i;
    			}
    		}
    	}
    	return;
    }
    
    inline void give_word(char a, char b)
    {
    	if(p1 == 3) {
    		for(int i = 1; i <= b-a-1; i++) 
    			for(int j = 1; j <= p2; j++) ans += '*';
    	}
    	else if(p1 == 1) {
    		if(p3 == 1) {
    			for(char i = a+1; i < b; i++)
    				for(int j = 1; j <= p2; j++) ans += i;
    		}
    		else {
    			for(char i = b-1; i > a; i--)
    				for(int j = 1; j <= p2; j++) ans += i;
    		}
    	}
    	else {
    		if(p3 == 1) {
    			for(char i = a+1; i < b; i++)
    				for(int j = 1; j <= p2; j++) ans += (i-32);
    		}
    		else {
    			for(char i = b-1; i > a; i--)
    				for(int j = 1; j <= p2; j++) ans += (i-32);
    		}
    	}
    }
    
    int main() {
    	p1 = read(), p2 = read(), p3 = read();
    	cin >> st;
    	int len = st.length();
    	for(int i = 0; i < len; i++) {
    		if(st[i] != '-') ans += st[i];
    		else {
    			if(st[i+1] >= '0' && st[i+1] <= '9' && st[i-1] >= '0' && st[i-1] <= '9') {
    				if(st[i+1] - st[i-1] == 1) continue;
    				else if(st[i+1] - st[i-1] <= 0) ans += st[i];
    				else {
    					give_number(st[i-1], st[i+1]);
    				}
    			}
    			else if(st[i+1] >= 'a' && st[i+1] <= 'z' && st[i-1] >= 'a' && st[i-1] <= 'z') {
    				if(st[i+1] - st[i-1] == 1) continue;
    				else if(st[i+1] - st[i-1] <= 0) ans += st[i];
    				else {
    					give_word(st[i-1], st[i+1]);
    				}
    			}
    			else ans += st[i];
    		}
    	}
    	cout << ans << endl;
    	return 0;
    }
    

    太菜了,打了近百行


    t3.矩阵取数游戏

    题目

    题意:一个n*m的矩阵,每次可以取走每一行的行首或者行末的一个元素, 每行取数的得分 = 被取走的元素值 * 2的已取元素次方(自行看题理解吧)

    思路:[区间dp] 早年凭借自己写出的若干道(<=10道)dp题目。正儿八经地题解我估计会另开一篇写,这里就简单口胡一下:开三维数组,分行处理这个矩阵,每行就是一个简单的区间dp。然后这样你就可以得到60分的高分。剩下40分就靠自己的高精呢(我才不会高精呢,试试__int128吧)

    Code:

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    //Mystery_Sky
    //
    #define M 10000100
    #define INF 0x3f3f3f3f
    #define ll __int128
    inline int read()
    {
    	int x=0;
    	int f=1;char c=getchar();
    	while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    ll f[81][81][81];
    int n, m;
    int a[81][81];
    ll Pow[81];
    ll ans;
    
    void print(ll x)
    {
    	if(x < 0) x = -x, putchar('-');
    	if(x > 9) print(x/10);
        putchar(x%10 + '0');
    }
    
    int main() {
    	n = read(), m = read();
    	for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= m; j++) a[i][j] = read();
    	Pow[0] = 1;
    	for(int i = 1; i <= m; i++) Pow[i] = Pow[i-1] * 2;
    	for(int k = 1; k <= n; k++) {
    		ll maxx = 0;
    		for(int len = m; len >= 1; len--) {
    			for(int i = 1; i + len - 1 <= m; i++) {
    				int j = i + len - 1;
    				int w = m - (j - i + 1);
    				if(i - 1 >= 1) f[i][j][k] = max(f[i][j][k], f[i-1][j][k] + a[k][i-1] * Pow[w]);
    				if(j + 1 <= m) f[i][j][k] = max(f[i][j][k], f[i][j+1][k] + a[k][j+1] * Pow[w]);
    			}
    		}
    		for(int i = 1; i <= m; i++) maxx = max(maxx, f[i][i][k] + a[k][i] * Pow[m]);
    		ans += maxx;
    	}
    	print(ans);
    	return 0;
    }
    

    还是很菜,lzx大佬60分做法只用了18行。


    t4.树网的核

    题目

    题意:如果你觉得这道题题意很繁琐,或者定义过于繁杂,可以看看这个->消防

    思路:不会,太复杂了,我太菜了,暴力都打不出,不然就有300分了


    总分:100 + 100 + 60 + 0.

    (update)t4.树网的核

    正解:(参考了《算法竞赛进阶指南》)
    树的直径的求法:任取一点,找到树上距离该点最远的结点p,再以p为起点找到距离p最远的结点q,p->q的路径即为树的一条直径。(证明略
    最小偏心距的求法:在直径上枚举长度不超过s的路径,暴力计算即可。
    优化:根据贪心的思想,求最小偏心距的时候,对于每个起点p,只需找到距离其最远的距离不超过s的点q即可。
    Code:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    //Mystery_Sky
    //
    #define INF 0x3f3f3f3f
    #define ll long long
    #define M 500
    inline 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*10+c-'0';c=getchar();}
        return x*f; 
    } 
    struct Edge{
        int next, to, w;
    }edge[5050];
    
    struct node{
        int dis, pos;
    };
    
    int n, s, dis_2[M], fa[M], vis[M], dis[M][M];
    int head[M], cnt;
    vector <int> d;
    
    inline void add_edge(int u, int v, int w)
    {
        edge[++cnt].to = v;
        edge[cnt].next = head[u];
        edge[cnt].w = w;
        head[u] = cnt;
    }
    
    void dfs_2(int p, int f)
    {
        fa[p] = f;
        for(int i = head[p]; i; i = edge[i].next) {
            int y = edge[i].to;
            if(y == f) continue;
            dis_2[y] = dis_2[p] + edge[i].w;
            dfs_2(y, p);
        }
    }
    
    inline void mark(int l, int r)
    {
        while(l != r) {
            d.push_back(l); 
            vis[l] = 1;
            l = fa[l];
        }
        vis[r] = 1;
        d.push_back(r); 
        return;
    }
    
    inline void clear_mark(int l, int r)
    {
        d.clear();
        while(l != r) {
            vis[l] = 0;
            l = fa[l];
        }
        vis[r] = 0;
        return;
    }
    
    inline int get_right(int p)
    {
        int pp = p;
        for(;;) {
            if(dis_2[p] - dis_2[fa[pp]] < s) pp = fa[pp];
            else if(dis_2[p] - dis_2[fa[pp]] == s) return fa[pp];
            else return pp;
        }
    }
    
    inline void floyd()
    {
        for(int i = 1; i <= n; i++) dis[i][i] = 0;
        for(int k = 1; k <= n; k++)
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= n; j++)
                    if(dis[i][j] > dis[i][k] + dis[k][j]) 
                        dis[i][j] = dis[i][k] + dis[k][j];
    }
    
    int main() {
        n = read(), s = read();
        memset(dis, INF, sizeof(dis));
        for(int i = 1; i <= n-1; i++) {
            int u = read(), v = read(), w = read();
            //if(u > v) swap(u, v);
            add_edge(u, v, w);
            add_edge(v, u, w);
            dis[u][v] = dis[v][u] = w;
        }
        floyd();
        node x;
        x.dis = 0;
        for(int i = 1; i <= n; i++) if(dis[1][i] > x.dis) x.dis = dis[1][i], x.pos = i;
        dfs_2(x.pos, 0);
        node y;
        y.dis = 0;
        for(int i = 1; i <= n; i++) if(dis_2[i] > y.dis) y.dis = dis_2[i], y.pos = i;//求出树直径的另一端点。
        dis_2[0] = -INF;    
        int l = y.pos;
        int ECC = INF;
        for(;;) {
            int r = get_right(l);
            mark(l, r);
            int len = d.size();
            int maxx = -1;
            for(int i = 1; i <= n; i++) {
                if(vis[i]) continue;
                else {
                    int D = INF;
                    for(int j = 0; j < len; j++) {
                        D = min(D, dis[i][d[j]]);
                    }
                    maxx = max(D, maxx); 
                }
            }
            ECC = min(maxx, ECC);
            if(r == x.pos) break;
            clear_mark(l, r);
            l = fa[l];
        }
        printf("%d
    ", ECC);
        return 0;
    }
    
  • 相关阅读:
    linux | 一次网卡故障处理
    KVM | centos 安装 window 虚拟机
    DNS | named.run文件很大的处理方法
    01
    802.11X用户身份验证
    802.11有线等效加密WEP
    802.11成帧细节
    802.11 MAC基础
    【转载】我为什么放弃了 Linux 内核学习?
    Linux网络编程(一):一个简单的socket程序
  • 原文地址:https://www.cnblogs.com/Benjamin-cpp/p/11745332.html
Copyright © 2011-2022 走看看