• 11.4 校内模拟赛解题报告


    T1

    尽量先找面额大的,然后找面额小的。

    int main()
    {
    	n = read();
    	for(int i = 1; i <= n; i++)
    	{
    		int x = read();
    		if(x == 5) a++;
    		if(x == 10)
    		{
    			if(a != 0) a--, b++;
    			else {puts("NO"); return 0;}
    		}
    		if(x == 20)
    		{
    			if(b != 0 && a != 0) a--, b--;
    			else if(a >= 3) a -= 3;
    			else {puts("NO"); return 0;}
    		}
    	}
    	puts("YES");
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    T2

    考场上写了一个用栈正序维护的错误做法,维护栈中每个数字的个数,和已知出口数字的个数,怎么看怎么对。但是并不对。
    正解:用栈倒叙维护,每次栈顶的绝对值与当前数的绝对值不相同,就将当前数变成负数进栈,如果相同且栈顶为负,则出栈。

    /*
    Date:
    Source:
    Knowledge: 用栈维护,倒着来 
    */
    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #define orz cout << "AK IOI" << "
    "
    
    using namespace std;
    const int maxn = 1e6 + 10;
    
    int read()
    {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch <= '9' && ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    void print(int X)
    {
    	if(X < 0) X = ~(X - 1), putchar('-');
    	if(X > 9) print(X / 10);
    	putchar(X % 10 ^ '0');
    }
    int Max(int a, int b){
    	return a > b ? a : b;
    }
    int Min(int a, int b){
    	return a < b ? a : b;
    }
    int n, m, a[maxn], vis[maxn];
    int top, st[maxn];
    int main()
    {
    	//freopen("program1.in", "r", stdin);
    	//freopen("program.out", "w", stdout);
    	n = read();
    	for(int i = 1; i <= n; i++) a[i] = read(), vis[a[i]]++;
    	for(int i = 1; i <= n; i++)
    		if(vis[a[i]] % 2 == 1) {puts("NO"); return 0;}
    	m = read();
    	for(int i = 1; i <= m; i++)
    	{
    		int x = read();
    		if(a[x] > 0) a[x] = -a[x];    	
    	}
    	for(int i = n; i >= 1; i--)
    	{
    		if(abs(st[top]) != abs(a[i])) 
    		{
    			if(a[i] > 0) st[++top] = -a[i], a[i] = -a[i];
    			else st[++top] = a[i];
    		}
    		else
    		{
    			if(a[i] > 0) top--;
    			else st[++top] = a[i];
    		}
    	} 
    	for(int i = 1; i <= n; i++) 
    	{
    		if(a[i] < 0) printf("%d ", a[i]);
    		else printf("+%d ", a[i]);
    	}
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    T3

    将钥匙看做左括号,门看做右括号,模拟括号匹配,将问题转化为 从 (a) 走到 (b) 能否完成括号匹配。

    宽搜 + DP。

    (f[i][j][k]) 表示点 (i) 到点 (j) 是否有状态 (k)
    (k = 0) 表示 (i)(j) 的路径上能够括号匹配。
    (k:1 — 10) 表示点 (i)(j) 的路径上,栈顶为右括号 (k)
    (k:11 — 20) 表示点 (i)(j) 的路径上,栈顶为左括号 (k),即缺右括号 (k)

    每次更新一个 (i j k),就相当于在 (i j) 之间连一条状态为 (k) 的边,让这条边进队。
    (w < 0) 的时候边是不进队的,因为有了左括号后可以接右括号,而右括号后不能接左括号。

    从队列里取出从 (u)(v) 的状态为 (w) 的边。
    如果 (w = 0),那么枚举状态 (k (0, 11—20)) 进行更新。
    如果 (w != 0),那么只能去找右括号。
    具体看代码。
    为什么 (w=0) 是双向更新,(w!=0) 是单项更新?
    因为只能是栈中有左括号的情况下,只有右括号才能入栈。
    对于每一次询问,判断 (f[u][v][0]) 即可。

    /*
    Date:
    Source:
    Knowledge:f[i][j][k] 表示点i到点j 是否有状态k
    */
    #include <iostream>
    #include <cstdio>
    #include <queue>
    #define orz cout << "AK IOI" << "
    "
    
    using namespace std;
    const int maxn = 110;
    
    int read()
    {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch <= '9' && ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    void print(int X)
    {
    	if(X < 0) X = ~(X - 1), putchar('-');
    	if(X > 9) print(X / 10);
    	putchar(X % 10 ^ '0');
    }
    int Max(int a, int b){
    	return a > b ? a : b;
    }
    int Min(int a, int b){
    	return a < b ? a : b;
    }
    int n, m, Q;
    bool f[maxn][maxn][25];
    struct node{
    	int u, v, w;
    };
    queue <node> q;
    int main()
    {
    	n = read(), m = read();
    	for(int i = 1; i <= n; i++) f[i][i][0] = 1; 
    	for(int i = 1; i <= m; i++)
    	{
    		int u = read(), v = read(), w = read();
    		if(w == 0)
    		{
    			f[u][v][w] = f[v][u][w] = 1;
                q.push((node){u, v, w}); 
                q.push((node){v, u, w}); 
    		}
    		else if(w > 0)//钥匙  
    		{
    			w += 10;
                f[u][v][w] = f[v][u][w] = 1;
                q.push((node){u, v, w}); 
                q.push((node){v, u, w}); 
    		}
    		else w = -w, f[u][v][w] = f[v][u][w] = 1; //门 
    	}
    	while(!q.empty())
    	{
    		node t = q.front();
    		q.pop();
    		int u = t.u, v = t.v, w = t.w;
    		if(w == 0)//大前提是已经有一条权值为 0 的边连通 u,v, 此时是一条有向边, 类比最短路。 
    		{
    			for(int i = 1; i <= n; i++)
    			{
    				if(f[i][u][0] && !f[i][v][0]) 
                	{
                	    f[i][v][0] = 1;
               	     	q.push((node){i, v, 0});
                	}
                	if(f[v][i][0] && !f[u][i][0])
                	{
                	    f[u][i][0] = 1;
                	    q.push((node){u, i, 0});
                	}
    				for(int k = 11; k <= 20; k++)
    				{
    					if(f[i][u][k] == 1 && !f[i][v][k]) f[i][v][k] = 1, q.push((node){i, v, k});
    					//if(f[i][v][k] == 1 && !f[i][u][k]) f[i][u][k] = 1, q.push((node){i, u, k});
    				}
    			}
    		}
    		else 
    		{
    			for(int i = 1; i <= n; i++)
                {
                    if(f[v][i][w - 10] && !f[u][i][0]) // w 属于(1 - 10) 并没有入队 
                    {
                        f[u][i][0] = 1;
                        q.push((node){u, i, 0});
                    }
                }
    		}
    	}
    	Q = read();
    	for(int i = 1; i <= Q; i++)
    	{
    		int a = read(), b = read();
    		if(f[a][b][0] == 1) puts("YES");
    		else puts("NO");
    	}
    	//fclose(stdin);
    	//fclose(stdout);
    	return 0;
    }
    
    
  • 相关阅读:
    动态传参
    函数的介绍
    文件的操作
    send email with formatted table
    minimize and close window with customed winform
    python algorithm
    something important about docker
    book list
    which language is suitable for what to do
    Find Duplicate Items in list fast
  • 原文地址:https://www.cnblogs.com/yangchengcheng/p/15509306.html
Copyright © 2020-2023  润新知