首页 > 其他分享 >【题解】做题记录(2022.8)

【题解】做题记录(2022.8)

时间:2022-08-13 14:27:44浏览次数:61  
标签:p2 p4 记录 int 题解 -- MAXN 2022.8 MOD

(之前的就暂时不补了就从以后的开始记)

8.12

CF1606C Banknotes

题目分析:
显然第 \(i\) 种货币可以用来组成 \(a_{i+1} - a_{i}\) 位,为了使得 \(k\) 最小,显然从低到高位依次填补是最优的。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 100;
int a[MAXN],ans[MAXN],pre[MAXN];
signed main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	for(int i=1; i<=10; i++)	pre[i] = pre[i-1] * 10 + 9;
	int t;
	scanf("%lld",&t);
	while(t--){
		int n,k;
		int tot = 0;
		scanf("%lld%lld",&n,&k);k++;
		for(int i=1; i<=n; i++)	scanf("%lld",&a[i]);
		for(int i=1; i<n; i++){
			if(pre[a[i+1] - a[i]] <= k)	k -= pre[a[i+1]-a[i]],ans[++tot] = pre[a[i+1]-a[i]];
			else if(k)	ans[++tot] = k,k=0;	
		}
		if(k)	ans[++tot] = k; 
		for(int i=tot; i>=1; i--)
			printf("%lld",ans[i]);
		printf("\n");
	}
	return 0;
}

总结:
做了一道大水题,水题数+1

*CF1606D Red-Blue Matrix

题目分析:
我们考虑如果只有一列的情况,那么我们将这一列的元素从大到小排序之后,显然我们的红色行是下面连续的一段。
那么我们就考虑将我们的矩阵按第一列排序,显然因为第一列的限制,我们的红色行也只能是下面连续的一段,然后就直接枚举选哪一段,以及左右矩阵的分割点是哪个就好了。
可以预处理出来矩阵的各个部分的最大值与最小值就可以实现 \(O(1)\) 的复杂度判断是否合法。

代码:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN=5e5+5;
vector<int> a[MAXN];
vector<int> p1[MAXN],p2[MAXN],p3[MAXN],p4[MAXN];
int n,m;
int p[MAXN];
char ans[MAXN];
bool flag[MAXN];
bool cmp(int l,int r){
	return a[l][1] < a[r][1];
}
void work(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n+1;i++){
        p1[i].clear();p2[i].clear();p3[i].clear();p4[i].clear();a[i].clear();
		p1[i].resize(m+5,0);p2[i].resize(m+5,(int)1e6);p3[i].resize(m+5,(int)1e6);p4[i].resize(m+5,0);a[i].resize(m+5,0);
	}
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) scanf("%d",&a[i][j]);
    for(int i=0; i<=n+1; i++)	p[i] = i,flag[i] = false;
    sort(p+1,p+1+n,cmp);
    for(int i=1;i<=n;i++)   //左上角到左下角的最大值 
        for(int j=1;j<=m;j++){
            p1[p[i]][j]=a[p[i]][j];
            p1[p[i]][j]=max(p1[p[i]][j],p1[p[i-1]][j]);
            p1[p[i]][j]=max(p1[p[i]][j],p1[p[i]][j-1]);
        }
    for(int i=1;i<=n;i++)   //左下角到右上角的左小指 
        for(int j=m;j>=1;j--){
            p2[p[i]][j]=a[p[i]][j];
            p2[p[i]][j]=min(p2[p[i]][j],p2[p[i-1]][j]);
            p2[p[i]][j]=min(p2[p[i]][j],p2[p[i]][j+1]);
        }
    for(int i=n;i>=1;i--)   //右上角到左下角的最小值 
        for(int j=1;j<=m;j++){
            p3[p[i]][j]=a[p[i]][j];
            p3[p[i]][j]=min(p3[p[i]][j],p3[p[i+1]][j]);
            p3[p[i]][j]=min(p3[p[i]][j],p3[p[i]][j-1]);
        }
    for(int i=n;i>=1;i--)  //右下角到左上角的最大值 
        for(int j=m;j>=1;j--){
            p4[p[i]][j]=a[p[i]][j];
            p4[p[i]][j]=max(p4[p[i]][j],p4[p[i+1]][j]);
            p4[p[i]][j]=max(p4[p[i]][j],p4[p[i]][j+1]);
        }
    for(int i=2; i<=n; i++){
        for(int j=1;j<=m-1;j++){
            if(p3[p[i]][j]>p1[p[i-1]][j]&&p2[p[i-1]][j+1]>p4[p[i]][j+1]){
                for(int k=n;k>=i;k--) flag[p[k]] = true;
                printf("YES\n");
                for(int k=1;k<=n;k++){
                	if(flag[k])	printf("R");
                	else	printf("B");
				}
                printf(" %d\n",j);
                return;
            }
        }
    }
    printf("NO\n");
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
    	work();
	}
    return 0;
}

总结:
考虑解决小的问题,并由小的问题推广到大问题,有利于发现题目性质。并且要善于观察数据范围。

*CF1606E Arena

题目分析:
我们读完题之后会发现英雄能不能全部干掉与最大值密切相关,那么我们就可以考虑设 \(f(i,j)\),表示有 \(i\) 个英雄,最大血量为 \(j\) 的最后全部被干掉的方案数。
转移也是相当显然的:

\[f(i,j) = \sum_{k=1}^i \binom{i}{k}f(k,j-(i-1)) \times (i-1)^{i-k} \]

也就是我们直接枚举这一轮剩下多少人,显然剩下的最大值就是 \(j-(i-1)\),而这一轮干掉的 \(i-k\) 个人显然血量为 \([1,i-1]\) 均可。

代码:

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 505;
const int MOD = 998244353;
int dp[MAXN][MAXN],c[MAXN][MAXN],pre[MAXN][MAXN];
int power(int a,int b){
    int res = 1;
    while(b){
        if(b & 1)   res = (res * a)%MOD;
        a = (a * a)%MOD;
        b>>=1;
    }
    return res;
}
signed main(){
    int n,x;
    scanf("%lld%lld",&n,&x);
    c[0][0] = 1;
    for(int i=1; i<=n; i++){
        c[i][0] = 1;
        for(int j=1; j<=n; j++){
            c[i][j] = (c[i-1][j-1] + c[i-1][j])%MOD;
        }
    }
    for(int i=1; i<=500; i++){
        pre[i][0] = 1;
        for(int j=1; j<=500; j++){
            pre[i][j] = (pre[i][j-1] * i)%MOD;
        }
    }
    for(int i=2; i<=n; i++){
        for(int j=1; j<=x; j++){
            if(i-1 >= j)
                dp[i][j] = ((pre[j][i] - pre[j-1][i])%MOD + MOD) % MOD;
            else{
                for(int k=1; k<=i; k++){
                    dp[i][j] = (dp[i][j] + ((c[i][k] * dp[k][j - (i-1)])%MOD * pre[i-1][i-k])%MOD)%MOD;
                }
            }
        }
    }
    int ans = 0;
    for(int i=1; i<=x; i++) ans = (ans + dp[n][i])%MOD;
    printf("%lld\n",ans);
    return 0;
}

可以预处理出来需要的幂,可以省掉一个 \(O(\log n)\) 的复杂度

总结:
不能看到一道题就肯定他是某种题目,如果一直将这个题当作数学题做,显然做不出来,就像我一样。也要重充分发挥预处理的功能。

标签:p2,p4,记录,int,题解,--,MAXN,2022.8,MOD
From: https://www.cnblogs.com/linyihdfj/p/16580351.html

相关文章