AtCoder Beginner Contest 379 题解

AtCoder Beginner Contest 379

Rated: 770

  • A - Cyclic

    简单模拟。

  • B - Strawberries

    字符串模拟,substr 函数秒了

  • C - Repeating

    中等模拟。
    思路:判断是否合法很简单,重点在计算花费。
    假设我们是 0 号点有 N 个棋子,然后移动到每个点上,显然花费为 N(N+1)2
    但是现在棋子不在 0 好点上,如果有一个 Ai 这个地方有 Bi 个棋子,那么就会省去 Ai×Bi 的花费。
    接下来排序,简单模拟即可。

  • D - Home Garden

    priority_queue + lazy_tag

  • E - Sum of All Substrings

    拆贡献法,第 i 个数的数为 ai,那么它左边选择的值会增加 i 种情况,而右边对答案产生 100+101+102++10ni 的贡献,
    i 位的总花费就是 j=1Nii×10j×ai 相当于给高精度的数 0Ni 位加上 i×ai
    差分处理,再处理一下进位即可

    点击查看代码
    #include<bits/stdc++.h>
    using namespace std;
    int n;
    long long ans[300001],c[200001];
    char s[200001];
    bool st;
    int main(){
    	scanf("%d%s",&n,s + 1);
    	for(int i = 1;i <= n;i ++){
    		c[i] = i * (s[i] - '0');
    	}
    	for(int i = n;i;i --){
    		ans[i] = ans[i + 1] + c[n - i + 1];//差分
    	}
    	for(int i = 1;i < 300000;i ++){//进位
    		ans[i + 1] += ans[i] / 10;
    		ans[i] = ans[i] % 10;
    	}
    	for(int i = 300000;i;i --){
    		if(ans[i]){//去除前导零
    			st = true;
    		}
    		if(st){
    			printf("%lld",ans[i]);
    		}
    	} 
    	return 0;
    }
    
  • F - Buildings 2

    性质:对于一对 (l,r),在 l 处能看到的位置大于 r 的楼房,在 r 处一定也能看到;在 r 处能看到的楼房,在 l 处不一定能看到。

    因此,(l,r) 都能看到的楼房一定是 l 能看到的位置大于 r 处的所有楼房。

    将询问离线,挂在 l 处。从序列最后倒着做一个单调栈,存着在当前点能够看到的楼房编号。

    那么在 l 处,对于所有以 l 为左端点的询问点对 (l,r),能看到的楼房个数就是当前单调栈中位置大于 r 的楼房个数,可以通过在单调栈上二分查找得到。

    最后按询问顺序输出答案即可。

    时间复杂度 O(nlogn)

    点击查看代码
    #include <bits/stdc++.h>
    using namespace std;
    typedef pair <int, int> pii;
    const int N = 1e6 + 10;
    int n, Q, a[N];
    int st[N], tot, ans[N];
    vector <pii> query[N];
    signed main () {
    	ios::sync_with_stdio (false);
    	cin.tie (0); cout.tie (0);
    
    	cin >> n >> Q;
    	for (int i = 1; i <= n; ++i) cin >> a[i];
    	for (int i = 1, l, r; i <= Q; ++i)
    		cin >> l >> r, query[l].emplace_back (r, i);
    	for (int i = n; i; --i) {
    		for (auto [j, id] : query[i]) {
    			int l = 1, r = tot;
    			while (l < r) {
    				int mid = (l + r + 1) >> 1;
    				if (st[mid] > j) l = mid;
    				else r = mid - 1;
    			}
    			if (st[l] <= j) ans[id] = 0; // 单调栈中不存在位置大于 j 的点
    			else ans[id] = l;
    		}
    		while (tot && a[st[tot]] < a[i]) --tot;
    		st[++tot] = i;
    	}
    	for (int i = 1; i <= Q; ++i) cout << ans[i] << endl;
    	return 0;
    }
    
  • G - Count Grid 3-coloring

    注意数据范围 n×m200,那么对于一组数据,min(n,m)200=14,这启发使用状压DP。

    选择行数或列数的较小值来进行状态压缩。

    fi,t 表示扫到第 i 行,且当前行的状态为 t 的方案数。如果 tt 不矛盾,我们使 fi,t+=fi1,t

    • 我们先预处理出每一行可以填什么(存到 vector 里)。
    • 转移:枚举上一行的每一个状态,然后在枚举这一行的每一个状态。
    • 初始值:f1,t=1
    • 答案: fn,t

    显然,滚动数组优化。

    时间复杂度:

    • a 数组值全为 1,那么情况数即为 3×2m1=24576m14)。
    • O(n×(3×2m1)2) ,但远远不会达到这个,有很多剪枝优化。
    点击查看代码
    #include <bits/stdc++.h>
    using namespace std;
    #define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
    #define ROF(i, a, b) for (int i = (a); i >= (b); --i)
    #define DEBUG(x) cerr << #x << " = " << x << endl
    #define ll long long
    typedef pair <int, int> PII;
    typedef unsigned int uint;
    typedef unsigned long long ull;
    #define i128 __int128
    #define fi first
    #define se second
    mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
    #define ClockA clock_t start, end; start = clock()
    #define ClockB end = clock(); cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
    //#define int long long
    inline int rd(){
    	int x = 0, f = 1;
    	char ch = getchar();
    	while (ch < '0' || ch > '9'){
    		if (ch == '-')
    			f = -1;
    		ch = getchar();
    	}
    	while (ch >= '0' && ch <= '9')
    		x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    	return x * f;
    }
    #define rd rd()
    
    void wt(int x){
    	if (x < 0)
    		putchar('-'), x = -x;
    	if (x > 9)
    		wt(x / 10);
    	putchar(x % 10 + '0');
    	return;
    }
    void wt(char x){
    	putchar(x);
    }
    void wt(int x, char k){
    	wt(x),putchar(k);
    }
    
    namespace Star_F{
    	const int N = 205, M = 5000000, MOD = 998244353;
    	int n,m;
    	char s[N][N];
    	int a[N][N], b[N], u;
    
    	vector<int> vec[N];
    	void dfs(int t){
    		if(t>m){
    			int nw=0;
    			for(int i=1;i<=m;i++) nw=nw*3+b[i];
    			vec[u].push_back(nw);
    			return;
    		}
    		if(a[u][t]!=-1 && a[u][t]!=b[t-1]){
    			b[t]=a[u][t];
    			dfs(t+1);
    		}
    		else if(a[u][t]==-1){
    			if(b[t-1]!=0) b[t]=0, dfs(t+1);
    			if(b[t-1]!=1) b[t]=1, dfs(t+1);
    			if(b[t-1]!=2) b[t]=2, dfs(t+1);
    		}
    	}
    
    	int sm,sum[N];
    	long long f[2][M];
    	void dfs2(int t){
    		if(t>m){
    			int nw=0;
    			for(int i=1;i<=m;i++) nw=nw*3+b[i];
    			f[u&1][nw]=(f[u&1][nw]+f[(u&1)^1][sm])%MOD;
    			return;
    		}
    		if(b[t-1]!=0 && sum[t]!=0) b[t]=0, dfs2(t+1);
    		if(b[t-1]!=1 && sum[t]!=1) b[t]=1, dfs2(t+1);
    		if(b[t-1]!=2 && sum[t]!=2) b[t]=2, dfs2(t+1);
    	}
    
    	void Main(){
    		cin >> n >> m;
    		memset(a,-1,sizeof(a));
    		for(int i=1;i<=n;i++){
    			cin >> s[i] + 1;
    			for(int j=1;j<=m;j++){
    				if(s[i][j]=='1') a[i][j]=0;
    				if(s[i][j]=='2') a[i][j]=1;
    				if(s[i][j]=='3') a[i][j]=2;
    			}
    		}
    		if(n<m){ //swap 
    			for(int i=1;i<=m;i++)
    				for(int j=1;j<i;j++)
    					swap(a[i][j],a[j][i]);
    			swap(n,m);
    		}
    		for(int i=1;i<=n;i++){
    			u=i,b[0]=-1,dfs(1);
    		}
    		for(auto i:vec[1]) f[1][i]=1;     //初始化
    		for(int i=2;i<=n;i++){
    			u=i;
    			for(int j:vec[i-1]){
    				sm=j;
    				for(int k=m;k>=1;k--) sum[k]=sm%3,sm/=3;
    				sm=j; 
    				b[0]=-1;
    				dfs2(1);
    			}
    			memset(f[(i&1)^1],0,sizeof(f[(i&1)^1]));
    		}
    
    		long long ans=0;
    		for(auto i:vec[n]) ans=(ans+f[n&1][i])%MOD;
    		cout << ans << endl;
    	}
    }
    
    signed main(){
    	// freopen(".in","r",stdin);
    	// freopen(".out","w",stdout);
    	ClockA;
    	int T=1;
    	// T=rd;
    	while(T--) Star_F::Main();
    	// ClockB;
    	return 0;
    }
    
    
posted @   Star_F  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示