zoukankan      html  css  js  c++  java
  • 20201104gryz模拟赛解题报告

    写在前面

    (Luckyblock) 良心出题人,
    题面好评
    T1还是蛮简单的,用一个栈来维护就能过(某天听说 (Luckyblock) 出了套题,T1是个考栈的,看来就是这道了
    注:栈的清空只需要把 (top) 置为 (0) 即可,没必要用 (memset)
    T2一开始打算单调栈+前缀和求惊喜度,但小数模法并不会,因此没写,暴力也不会打,看到正解后考虑到我的解法可能会被卡
    T3暴力不知道为啥写挂了
    T4输入的时候没读题,输入的 (x)(y) 多打了一组,所以 (10) 也没骗到,后面 (2h) 一直在推DP式


    T1 大空魔术

    简述题意:
    给你一串由 (A)(B) 组成序列, (AB)(BB) 形式可以发生对毁,问剩下的序列最短多长
    (Solution)
    发现 (?B) 是可以对毁的,考虑开一个栈,每读到一个元素,和栈顶元素比较,如果栈顶元素是 (A)(B) 且读到元素是 (B) ,就弹出栈顶元素,否则放入栈中,最后输出栈内元素个数
    正确性:发现 (B) 与谁都能对毁,因此在前面对毁的越多,对结果越有利

    /*
    Work by: Suzt_ilymics
    Knowledge: ??
    Time: O(??)
    =============================Luckyblock AK IOI===========================================
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    using namespace std;
    const int MAXN = 2e6+6;
    int T, n;
    char stc[MAXN];
    int top = 0;
    string s;
    
    int main()
    {
    //	freopen("a.in","r",stdin);
    //	freopen("a.out","w",stdout);
    	scanf("%d", &T);
    	while(T--){
    		top = 0;
    		cin>>s;
    		int len = s.size();
    		for(int i = 0; i < len; ++i){
    			if((stc[top] == 'A' && s[i] == 'B') || (stc[top] == 'B' && s[i] == 'B')){
    				top--;
    			}
    			else{
    				stc[++top] = s[i];
    			}
    		}
    		printf("%d
    ", top);
    	}
    	return 0;
    }
    
    

    T2夜桜街道

    简述题意:求给定的 (f(l,r)) 即为区间 ([l,r]) 内的顺序对个数。(顺序对定义与逆序对定义相反)
    求:

    [sum_{i=1}^{n}dfrac{f(1,i)}{i} pmod {998244353} ]

    Solution:

    考虑如何通过 (sum_{i=1}^{n-1} f(1,i)) 得到 (sum_{i=1}^{n} f(1,i))
    发现新增的贡献即为较大的数为 (a_n) 的顺序对。

    先离散化方便统计,然后枚举整个序列,用树状数组进行维护,统计答案是乘上逆元即可

    /*
    Work by: Suzt_ilymics
    Knowledge: ??
    Time: O(??)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define int long long
    using namespace std;
    const int MAXN = 1e6+5;
    const int mod = 998244353;
    int n, d_num, ans, f;
    int a[MAXN];
    int date[MAXN];
    int inv[MAXN];
    
    int read(){
    	int s = 0, w = 1; 
    	char ch = getchar();
    	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
    	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
    	return s * w;
    }
    
    namespace Bit{
    	#define lowbit(i) i & (-i)
    	int lim, tree[MAXN];
    	void init(int lim_) {  lim = lim_; }
    	void add(int x){
    		for(int i = x; i <= lim; i += lowbit(i)){
    			tree[i]++;
    		}
    	}
    	int get_sum(int x){
    		int ret = 0;
    		for(int i = x; i > 0; i -= lowbit(i)){
    			ret +=  tree[i];
    		}
    		return ret;
    	}
    }
    
    signed main()
    {
    	n = read();
    	inv[1] = 1;
    	for(int i = 1; i <= n; ++i){
    		date[i] = a[i] = read();
    		if(i > 1) inv[i] = (mod - mod / i) * inv[mod % i] % mod; 
    	}
    	sort(date + 1, date + n + 1);
    	d_num = 1;
    	for(int i = 2; i <= n; ++i) {
    		if(date[i] != date[i - 1]) ++d_num;
    		date[d_num] = date[i];//驱虫 
    	}
    	for(int i = 1; i <= n; ++i){
    		a[i] = lower_bound(date + 1, date + d_num + 1, a[i]) - date;
    	}
    	Bit::init(d_num);
    	for(int i = 1; i <= n; ++i){
    		f = (f + 1 * Bit::get_sum(a[i] - 1)) % mod;
    		ans = (ans + f * inv[i] % mod) % mod;
    		Bit::add(a[i]); 
    	}
    	printf("%lld
    ", ans);
    	return 0;
    }
    
    

    T4 萃香抱西瓜

    简述题意:简化不动
    (Solution)
    稍有点细节的状压 DP。

    读入时对所有时刻所有位置进行标记,记录是否有大小西瓜。

    发现小西瓜个数较小,考虑状压一下获得的小西瓜状态。
    (s_{t,x,y}) 表示 (t) 时刻,位置 ((x,y)) 的小西瓜的存在状态。
    (f(t,x,y,S)) 表示,在时间 (t),萃香的位置在 ((x,y)),获得的小西瓜状态为 (S) 时,需要移动的最小步数。

    初始化 (f(1,sx,sy,s1,sx,sy)=0),所有不可到达状态的 (f=Inf)

    转移时枚举每个时刻每个位置,从能到达该位置的上个时刻的位置 ((x′,y′)) 转移过来,还需要枚举上个位置的小西瓜状态,有:

    (f(t,x,y,S|s_{t,x,y})=min{f(t−1,x′,y′,S)}+1)
    统计答案时枚举最后一个时刻的所有取完所有小西瓜的状态,取最小值即可。

    复杂度 (O(Thw2^m)),数据范围小可以随便过。

    不是很懂,所以直接搬的题解(逃
    (Luckyblock变量名好评

    /*
    Work by: Suzt_ilymics
    Knowledge: ??
    Time: O(??)
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAXALL = 0x3f3f3f3f; 
    const int kMAX = (1 << 10) + 1; 
    int dx[5] = {0, 0, 0, 1, -1};
    int dy[5] = {0, 1, -1, 0, 0};
    int h, w, T, sx, sy;
    int n, m, sum = 0;
    int a[6][6][110];
    int f[6][6][110][kMAX];
    
    int read(){
    	int w = 1, s = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') w = -1; ch = getchar(); }
    	while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
    	return s * w;
    }
    
    int main()
    {
    //	freopen("d.in","r",stdin);
    //	freopen("d.out","w",stdout);
    	h = read(), w = read(), T = read(), sx = read(), sy = read();
    	n = read(), m = read();
    	for(int i = 1, t1_ = 0, t2_ = 0, a_ = 0; i <= n; ++i){
    		t1_ = read(), t2_ = read(), a_ = read();
    		if(a_) sum++;
    		for(int j = t1_, x, y; j < t2_; ++j){
    			x = read(), y = read();
    			if(a_ == 0){ a[x][y][j] = -1; }
    			else{ a[x][y][j] = (1 << (sum - 1)); }	
    		}
    	}
    	if(a[sx][sy][1] == -1) {
    		printf("-1"); return 0;
    	}
    	int all = (1 << m) - 1;
    	memset(f, 0x3f, sizeof(f));
    	f[sx][sy][1][a[sx][sy][1]] = 0;//初始化
    	for(int i = 2; i <= T; ++i){
    		for(int x = 1; x <= w; ++x){
    			for(int y = 1; y <= h; ++y){
    				if(a[x][y][i] == -1) continue;
    				for(int fx = 0; fx <= 4; ++fx){
    					int x_ = x + dx[fx], y_ = y + dy[fx];
    					if(x_ < 1 || x_ > w || y_ < 1 || y_ > h) continue;
    					if(a[x_][y_][i - 1] == -1) continue;
    					for(int k = 0; k <= all; ++k){
    						f[x][y][i][k | a[x][y][i]] = min(f[x][y][i][k | a[x][y][i]], f[x_][y_][i -1][k] + (fx > 0));
    					}
    				}
    			}
    		}
    	} 
    	int ans = f[0][0][0][0];
    	for(int x = 1; x <= w; ++x){
    		for(int y = 1; y <= h; ++y){
    			ans = min(ans, f[x][y][T][all]);
    		}
    	}
    	printf("%d
    ", ans < MAXALL ? ans : -1);
    	return 0;
    }
    
    
  • 相关阅读:
    查找1
    动态规划
    分治
    [LeetCode] 1339. Maximum Product of Splitted Binary Tree
    [LeetCode] 1509. Minimum Difference Between Largest and Smallest Value in Three Moves
    [LeetCode] 233. Number of Digit One
    [LeetCode] 1963. Minimum Number of Swaps to Make the String Balanced
    [LeetCode] 1053. Previous Permutation With One Swap
    [LeetCode] 1962. Remove Stones to Minimize the Total
    [LeetCode] 1961. Check If String Is a Prefix of Array
  • 原文地址:https://www.cnblogs.com/Silymtics/p/13928550.html
Copyright © 2011-2022 走看看