220908 总结

220908 总结

预计:\(100+100+?\)

实际:\(90+10+30\)

T1 Z 君的密码

一道巨简单的模拟

开始理解错题意了以为是字符映射那样子

但是看了看样例发现相同字符对应的字符不一样...

重读题,跟着样例才明白,是该组内的字符在原串的位置的移动

T1 写了 45min 不知道说点什么好了(

乐了 因为测试文件读写的时候写错文件名没结果所以把 scanf/printf 换成了 cin/cout ,导致最后 TLE 了一个点 关了流同步就过了

T2 保护费

\(\text{protected}\) 的道路边权为 \(0\)\(\text{unprotected}\) 的道路边权为 \(1\)

由于这是一棵树,所以可以保证从 \(1\) 号城市开始可以把所有城市都经过恰好一次。

显然如果到某个城市是不安全的话应该缴纳离 \(1\) 号城市最近的危险边的保护费。

那么就可以从 \(1\) 号城市进行 DFS ,

如果当前城市到达下一个城市是不安全的,那么缴纳当前边的保护费并将该边修改为 \(\text{protected}\)

但是这个思路并不是正确的,无法正确解答如下图的情况

graphpng

正解是 DFS 的同时维护经过的所有危险边,如果当前点是不安全的,则将队列中第一条边缴纳保护费并移出队列(因为危险边在队列中的顺序即为离 \(1\) 号城市的远近)

由于交保护费是需要队列头出队,DFS 回溯需要从队尾删边,所以最好使用双端队列。

#include<bits/stdc++.h>
using namespace std;

const int maxN = 2e5 + 10;

struct Edge {
    int u, v, sf;
    Edge(int u, int v, int w): u(u), v(v), sf(w) {};
    friend bool operator == (Edge A, Edge B) {
        return A.u == B.u && A.v == B.v;
    }
};

vector<Edge> G[maxN];

int N, E;

int cnt;

deque<Edge> Q;

void dfs(int k, int fa, int dep) {
    while (dep < int(Q.size()) << 1) {
        Q.pop_front();
        cnt++;
    }
    for (auto i : G[k]) {
        if (i.v == fa) continue;
        if (i.sf == 1) Q.push_back(i);
        dfs(i.v, k, dep + 1);
        if(!Q.empty() && Q.back() == i) Q.pop_back();
    }
}

char S[50];

int main() {
    freopen("protect.in", "r", stdin);
    freopen("protect.out", "w", stdout);

    scanf("%d%d", &N, &E);
    for (int i = 1; i < N; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        scanf("%s", S);
        int us = S[0] == 'u';
        G[u].push_back(Edge(u, v, us));
        G[v].push_back(Edge(v, u, us));
    }
    dfs(1, 0, 0);

    printf("%lld", 1ll * cnt * E);
    return 0;
}

T3 疏导交通

当大模拟做的

先用四个方向的优先队列输入车辆信息并自动按到达时间排序。

对于每个时间 \(t\) ,先将当前时刻能到达的车分别放入四个方向的等待队列

然后检查四个方向等待队列内的车的数量并找到最大值

那么这一秒就应该开等待车数最多的方向的红绿灯

每秒每个单向只能放走一辆车。

放完车后,统计四个方向等待队列的车的数量 \(s\) ,这一秒每辆车等待 \(1s\) ,总等待用时增加 \(s\)

然后检查四个方向的车辆数

然后就只得了 \(30\) pts /kel

正解是五维 dp

看了 !樱雪! 神仙的码 直接大受震撼

牺牲一点性能换来了更高的可读性(然后就明白了应该怎么转移

#include<bits/stdc++.h>
using namespace std;

#define openNS (!(nextNextNum[1]>L||nextNextNum[2]>L||nextNum[3]>L||nextNum[4]>L))
#define openWE (!(nextNum[1]>L||nextNum[2]>L||nextNextNum[3]>L||nextNextNum[4]>L))

const int maxN = 210;
const int maxL= 6;
const int maxT = 70;
const int INF = 0x7f7f7f7f;

int N,L;

int cnc(char c){
	if(c == 'N') return 1;
	if(c == 'S') return 2;
	if(c == 'W') return 3;
	return 4;
}

struct Car{
	int from,t;
	
	Car(){};
	Car(char fro,int t):from(cnc(fro)),t(t){};
	
	friend bool operator < (Car A,Car B){
		return A.t < B.t;
	}
}C[maxN];

int dp[maxT][maxL][maxL][maxL][maxL];

int waitingNum[maxL];//四个方向等待车数
int nextNum[maxL];//四个方向来车后的等待车数
int nextNextNum[maxL];//四个方向来车后走了一辆的等待车数

int main(){
	freopen("traffic.in","r",stdin);
	freopen("traffic.out","w",stdout);
	
	scanf("%d%d",&N,&L);
	
	for(int i = 1;i<=N;i++){
		getchar();
		int T;
		char X;
		scanf("%c%d",&X,&T);
		C[i] = Car(X,T);
	}
	sort(C+1,C+1+N);

	memset(dp,0x7f,sizeof(dp));
	dp[0][0][0][0][0] = 0;
	
	int p = 1;
	
	for(int t = 1;t<=60;t++){
		memset(waitingNum,0,sizeof(waitingNum));
		while(C[p].t == t){
			waitingNum[C[p].from]++;
			p++;
		}
		
		for(int i = 0;i<=L;i++)
		for(int j = 0;j<=L;j++)
		for(int k = 0;k<=L;k++)
		for(int l = 0;l<=L;l++){
			if(dp[t-1][i][j][k][l] == INF) continue;
			
			int Tt[] = {0,i,j,k,l};
			for(int r = 1;r<=4;r++){
				nextNum[r] = Tt[r] + waitingNum[r];
				nextNextNum[r] = max(nextNum[r]-1,0);
			}
			if(openNS){
				int a = nextNextNum[1];
				int b = nextNextNum[2];
				int c = nextNum[3];
				int d = nextNum[4];
				dp[t][a][b][c][d] = min(dp[t][a][b][c][d],dp[t-1][i][j][k][l]+a+b+c+d);
			}
			if(openWE){
				int a = nextNum[1];
				int b = nextNum[2];
				int c = nextNextNum[3];
				int d = nextNextNum[4];
				dp[t][a][b][c][d] = min(dp[t][a][b][c][d],dp[t-1][i][j][k][l]+a+b+c+d);
			}
		}
	}
	
	int mi = INF;
	for(int i = 0;i<=L;i++)
	for(int j = 0;j<=L;j++)
	for(int k = 0;k<=L;k++)
	for(int l = 0;l<=L;l++){
		mi = min(mi,dp[60][i][j][k][l]);
	}
	
	if(mi == INF) printf("No solution");
	else printf("%d",mi);
	return 0;
}

总结

  • “反正样例过了” 的心态不可取,应该主动思考算法是不是假了

  • 远离没关流同步的 cin/cout ,会变得不幸

  • 想用贪心首先要考虑能不能找到不适用贪心的证据,找不到再用

posted @ 2022-09-09 10:34  Burnling  阅读(34)  评论(0编辑  收藏  举报