• CDZSC_2022寒假个人训练赛21级(7)题解


    • 简单
      • C gcd
      • D 模拟
      • E
    • 中等
      • A 01背包
      • I 贪心
    • 困难
      • B 线段树/树状态数组 区间查询+区间修改
      • F dfs+最优性剪枝+状态压缩
      • G 矩阵快速幂
      • H 素数筛法

    A Charm Bracelet POJ - 3624

    题意

    给你N个物品,每个具有Wi重量和Di价值,问你在不超过M的总重量前提下,能获得的最大价值是多少?

    题解

    01背包裸题

    AC代码

    int dp[13885];
    struct xxx {
    	int w, d;
    }s[4005];
    
    int main() {
    	int n, m,x,y;
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d%d", &x, &y);
    		s[i].w = x, s[i].d = y;
    	}
    	for (int i = 1; i <= n; i++) {
    		for (int j = m; j >0 ; j--) {
    			if (j >= s[i].w)
    				dp[j] = max(dp[j], dp[j - s[i].w] + s[i].d);
    			else dp[j] = dp[j];
    		}
    	}
    	printf("%d\n", dp[m]);
        return 0;
    }
    
    

    B A Simple Problem with Integers POJ - 3468

    题意

    给定数组,和一组操作,操作有两种,一种是数组区间加上一个值,一种是求数组区间和。

    题解

    线段树/树状数组 区间修改,区间查询裸题。

    AC代码

    //线段树
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<ctime>
    #include<string>
    #include<vector>
    #include<map>
    #include<list>
    #include<set>
    #include<stack>
    #include<bitset>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    
    struct tree {
    	ll sum, laz;
    	ll l, r;
    }t[400005];
    
    
    void pushup(ll p) {
    	t[p].sum = t[p * 2].sum + t[p * 2 + 1].sum;
    }
    void pushdown(ll p) {
    	t[p * 2].sum += t[p].laz*(t[p*2].r-t[p*2].l+1);
    	t[p * 2 + 1].sum += t[p].laz*(t[p * 2+1].r - t[p * 2+1].l + 1);;
    	t[p * 2].laz += t[p].laz;
    	t[p * 2 + 1].laz += t[p].laz;
    	t[p].laz = 0;
    }
    
    
    void build(ll l, ll r, ll p) {
    	t[p].l = l;
    	t[p].r = r;
    	t[p].sum = 0;
    	t[p].laz = 0;
    	if (l == r) {
    		scanf("%lld", &t[p].sum);
    		return;
    	}
    	ll mid = l + r >> 1;
    	build(l, mid, p * 2);
    	build(mid+1, r, p * 2+1);
    	pushup(p);
    }
    
    
    void update(ll L, ll R,ll k ,ll p) {
    	ll l = t[p].l, r = t[p].r;
    	if (L <= l && r <= R) {
    		t[p].sum += (r - l + 1)*k;
    		t[p].laz += k;
    		return;
    	}
    	pushdown(p);
    	ll mid = l + r >> 1;
    	if (L <= mid)update(L, R, k, p * 2);
    	if(R>mid) update(L, R, k, p * 2 + 1);
    	pushup(p);
    }
    
    ll query(ll L, ll R, ll p) {
    	ll l = t[p].l, r = t[p].r;
    	if (L <= l && r <= R) {
    		return t[p].sum;
    	}
    	pushdown(p);
    	ll mid = l + r >> 1;
    	ll ans = 0;
    	if (L <= mid)ans += query(L, R, p * 2);
    	if (R > mid)ans += query(L, R, p * 2 + 1);
    	pushup(p);
    	return ans;
    }
    
    int main() {
    	ll n,m;
    	scanf("%lld%lld", &n, &m);
    	build(1, n, 1);
    	char com;
    	ll l, r, k;
    	while (m--) {
    		scanf(" %c", &com);
    		if (com == 'Q') {
    			scanf("%lld%lld", &l, &r);
    			printf("%lld\n", query(l, r, 1));
    		}
    		else {
    			scanf("%lld%lld%lld", &l, &r, &k);
    			update(l, r, k, 1);
    		}
    	}
    }
    
    //树状数组
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #include<algorithm>
    #define lowbit(x) (x)&(-x)
    using namespace std;
    typedef long long ll;
    ll tree[100005], c[100005];
    void updata(ll i, ll x, ll*tree) {
    	while (i <= 100005) {
    		tree[i] += x;
    		i += lowbit(i);
    	}
    }
    
    void updata(ll l, ll r, ll x) {
    	updata(l, x, tree);
    	updata(r + 1, -x, tree);
    	updata(l, (l - 1) * x, c);
    	updata(r + 1, -r * x, c);
    }
    
    ll query(ll x, ll *tree) {
    	ll ans = 0;
    	while (x > 0) {
    		ans += tree[x];
    		x -= lowbit(x);
    	}
    	return ans;
    }
    
    ll query(ll x) {
    	return x * query(x, tree) - query(x, c);
    }
    ll query(ll l, ll r) {
    	return query(r) - query(l - 1);
    }
    ll s[100005];
    
    int main() {
    	int n, q;
    	char com;
    	int l, r, x;
    	scanf("%d%d", &n,&q);
    	for (ll i = 1; i <= n; i++) {
    		scanf("%lld", s + i);
    
    	}
    	for (ll i = 1; i <= n; i++) {
    		updata(i, s[i] - s[i - 1], tree);
    		updata(i, (i-1)*(s[i] - s[i - 1]), c);
    	}
    	while (q--) {
    		scanf(" %c", &com);
    		if (com == 'Q') {
    			scanf("%d%d", &l, &r);
    			printf("%lld\n",query(l, r));
    		}
    		else if (com == 'C') {
    			scanf("%d%d%d", &l, &r,&x);
    			updata(l, r, x);
    		}
    	}
    
    }
    
    

    C Visible Lattice Points POJ - 3090

    题意

    输入n,问从坐标(0,0)点能看到多少点,点的坐标范围是0<=(x,y)<=n
    只有一个点没有被另一个点挡住才能看到。

    题解

    枚举gcd判断是否被遮挡,如果两个数gcd不为1,说明,有比它更小的同比例的点,会遮挡它,多个查询,打表后输出就好。

    AC代码

    #include<iostream>
    
    using namespace std;
    
    int gcd(int a, int b) {
    	return b == 0 ? a : gcd(b, a%b);
    }
    const int max_n = 1000;
    int b[max_n+5];
    
    int main() {
    	int T, n;
    	scanf("%d", &T);
    	int ans = -1;
    	for (int i = 1; i <= max_n; i++) {
    		
    		for (int j = 0; j <= i; j++) {
    			if (gcd(i, j) == 1)ans++;
    			if (gcd(j, i) == 1)ans++;
    		}
    		b[i] = ans;
    	}
    
    
    	for (int t = 1; t <= T; t++) {
    		scanf("%d", &n);
    		printf("%d %d %d\n",t,n,b[n]);
    	}
    
    
    	return 0;
    }
    

    D Coder CodeForces - 384A

    题意

    给出n,在一个n * n的棋盘,要求在这个棋盘上方尽量多的棋子,棋子不能相邻,给出摆法。

    题解

    简单模拟,交替输出.和C就好

    AC代码

    int main() {
    	int n;
    	scanf("%d", &n);
    	printf("%d\n", (n*n+1)/2);
    	for (int i = 0; i < n; i++) {
    		for (int j = 0; j < n; j++) {
    			putchar((i+j&1)?'.':'C');
    		}
    		putchar('\n');
    	}
    
    }
    

    E Minimum Binary Number CodeForces - 976A

    题意

    给一个长为n的序列,每次都可以做两种操作之一:

    1. 把一对0和1的位置互换;
    2. 把11变成1
      输出一个可以获得的最短序列。
      (如果最短序列中有1和0,1一定先于0出现,例如100而不是001)

    题解

    所有的1都可以通过1、2操作变成一个1,然后把剩下0输出就好

    AC代码

    int main() {
    	int n;
    	int a = 0, b = 0,x;
    	scanf("%d", &n);
    	for (int i = 0; i < n; i++) {
    		scanf("%1d", &x);
    		if (x)a++;
    		else b++;
    	}
    	if (a)printf("1");
    	while (b--)printf("0");
    	printf("\n");
    }
    

    F 海贼王之伟大航路 OpenJ_Bailian - 4124

    题解

    dfs+最优性剪枝+状态压缩
    两个剪枝

    1. 目前的路程超过以及求出的一个可达路程,那直接可以剪掉。

      if (sum >= ans)return; 
      
    2. 保存所有状态中最优的那个路径,如果出现了一种状态的新路径并且路径更短那么更新它,如果更长则剪掉。 状态使用二进制和一个编号来表示,比如状态sta[0101][b],表示目前以及经过了第1个和第3个岛屿(0101=\(1^1+2^0+4^1+8^0\),在第一个位置上是1,第三个位置也是1,所以表示以及经过1,3岛屿这就是状态压缩,或者说二进制压缩),目前在第b个岛屿。这样子的表示能把所有状态划分。

      if (sta[tmp][x] > sum) {
      			sta[tmp][x] = sum;
      			dfs(i, k + 1);
      		}
      

    AC代码

    int s[20][20];
    int vis[20];
    int n, ans = 1e9;
    int sta[100005][20];
    int tmp = 0;
    int sum = 0;
    void dfs(int x, int k) {
    	if (x == n) {
    		if (k == n) {
    			ans = min(ans, sum);
    		}
    		return;
    	}
    	if (sum >= ans)return;
    
    
    	for (int i = 2; i <= n; i++) {
    		if (vis[i] == 0) {
    			vis[i] = 1;
    			tmp += 1 << (i - 2);
    			sum += s[x][i];
    
    			if (sta[tmp][x] > sum) {
    				sta[tmp][x] = sum;
    				dfs(i, k + 1);
    			}
    			
    			sum -= s[x][i];
    			tmp -= 1 << (i - 2);
    			vis[i] = 0;
    		}
    	}
    
    }
    
    int main() {
    
    	while (~scanf("%d", &n)) {
    		memset(vis, 0, sizeof vis);
    		memset(sta, 0x3f, sizeof sta);
    		ans = 1e9;
    		tmp = 0;
    		sum = 0;
    		for (int i = 1; i <= n; i++) {
    			for (int j = 1; j <= n; j++) {
    				scanf("%d", &s[i][j]);
    			}
    		}
    		dfs(1, 1);
    		printf("%d\n", ans);
    	}
    
    	return 0;
    
    }
    

    G Fibonacci POJ - 3070

    题意

    菲波那契数列是指这样的数列: 数列的第一个是0和第二个数是1,接下来每个数都等于前面2个数之和。 给出一个正整数a,要求菲波那契数列中第a个数的后四位是多少。

    题解

    矩阵快速幂,
    具体可以看我的另一篇博客从斐波那契到矩阵快速幂

    AC代码

    #include<iostream>
    
    using namespace std;
    
    int n,b[100005];
    
    typedef long long ll;
    const ll mod = 10000;
    const int N = 2;//矩阵大小
    int c[N][N];
    //状态转移
    void mul(ll f[N], ll a[N][N]) {
        ll c[N];
        memset(c, 0, sizeof(c));
        for (int j = 0; j < N; j++)
            for (int k = 0; k < N; k++)
                c[j] = (c[j] + f[k] * a[k][j]) % mod;
        memcpy(f, c, sizeof(c));
    }
    //自乘
    void mulself(ll a[N][N]) {
        ll c[N][N];
        memset(c, 0, sizeof(c));
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++)
                for (int k = 0; k < N; k++)
                    c[i][j] = (c[i][j] + (a[i][k] * a[k][j])) % mod;
        memcpy(a, c, sizeof(c));
    }
    
    //f是状态矩阵,a是转移矩阵,n是指数
    ll* pow(ll f[N], ll a[N][N],ll n) {
    
        while (n) {
            if (n & 1)mul(f, a);
            mulself(a);
            n >>= 1;
        }
        return f;
    }
    
    int main(){
    	int x;
    
    	while(scanf("%d",&x),x!=-1){
    		ll a[][2]={
    			{0,1},
    			{1,1}
    		};
    		ll f[]={0,1};
    		printf("%d\n",*pow(f,a,x));
    	}
    
    
    	
    
    
    }
    

    H Prime Distance POJ - 2689

    题意

    求给定区间内的质数距离最小的一对和质数距离最大的一对。

    题解

    先筛出\(\sqrt{2147483647}\) 以内的素数,然后用这些素数就可以筛出范围区间素数。
    实际上 \(N\) 以内的合数都是由 \(\sqrt{N}\) 以内的数构成的,很容易证明,因为如果你有个合数是由\(sqrt{N}\)以外的素数组成,我们假如组成这个合数的两个素数是 \(a=(\sqrt{N}+a),b=(\sqrt{N}+b)\),那\(a*b=(\sqrt{N}+a)*(\sqrt{N}+b)\)肯定是大于\(N\)的。
    第二次筛法,和第一次差不多,把在范围内的已经算出的素数的倍数,筛去,剩下的就是素数了。

    AC代码

    #include<iostream>
    #include<vector>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    ll vis[1000006];
    ll p[100005];
    
    ll e(ll n) {
    	for (ll i = 2; i*i <= n; i++)
    		if (!vis[i])
    			for (ll j = i * i; j <= n; j += i)
    				vis[j] = 1;
    	ll k = 0;
    	for (ll i = 2; i <= n; i++)
    		if (!vis[i])
    			p[k++] = i;
    	return k;
    }
    
    ll p2[1000005];
    ll vis2[1000005];
    void pab(ll a, ll b, ll k) {
    	ll i, j, x;
    	memset(vis2, 0, sizeof vis2);
    
    	for (i = 0; i < k; i++) {
    		x = a / p[i];
    		if (x <= 1)x = 2;
    		for (j = p[i] * x; j <= b; j += p[i]) {
    			if (j >= a)
    				vis2[j - a] = 1;
    
    		}
    
    	}
    	if (a == 1)
    		vis2[0] = 1;
    
    
    }
    
    int main() {
    	ll k = e(100000);
    
    	ll l, r, mx, mn, mxa, mxb, mna, mnb, c;
    	while (~scanf("%lld%lld", &l, &r)) {
    		mx = -INF;
    		mn = INF;
    		pab(l, r, k);
    		ll n = 0;
    		for (ll i = 0; i <= r - l; i++)
    			if (vis2[i] == 0) {
    				p2[n++] = i + l;
    			}
    		if (n <= 1)printf("There are no adjacent primes.\n");
    		else {
    
    			for (ll i = 0; i < n - 1; i++) {
    				if (p2[i + 1] - p2[i] > mx) {
    					mx = p2[i + 1] - p2[i];
    					mxa = p2[i];
    					mxb = p2[i + 1];
    				}
    				if (p2[i + 1] - p2[i] < mn) {
    					mn = p2[i + 1] - p2[i];
    					mna = p2[i];
    					mnb = p2[i + 1];
    				}
    
    			}
    			printf("%lld,%lld are closest, %lld,%lld are most distant.\n", mna, mnb, mxa, mxb);
    		}
    	}
    
    
    }
    

    I Intercepted Message CodeForces - 950B

    题意

    给定两个长度分别为 \(n,m\) 的序列 \(x_1,x_2,⋯,x_n\)\(y_1,y_2,⋯,y_m\),要将序列 \(X\) 和序列 \(Y\) 分别划分成若干段,使得序列 \(X\) 的第 \(i\) 段数字的和等于序列 \(Y\) 的第 \(i\) 段数字的和,问最多能够分成多少段。

    题解

    贪心
    整两个和\(sum_1,sum_2\),从分别两个数组的开头慢慢加,哪个小先加哪个,相同了就将答案加一。

    AC代码

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    int a[100005], b[100005];
    
    int main() {
    	int n, m;
    	scanf("%d%d", &n, & m);
    	for (int i = 0; i < n; i++)
    		scanf("%d", a + i);
    	for (int i = 0; i < m; i++)
    		scanf("%d", b + i);
    	int sum1 = a[0], sum2 = b[0],x=0,y=0;
    	int ans =1;
    	while (1) {
    		if (x >= n-1 && y >= m-1)break;
    		else if (sum1 == sum2) {
    			ans++;
    			x++, y++;
    			sum1 += a[x];
    			sum2 += b[y];
    
    		}
    		else if (sum1 > sum2) {
    			y++;
    			sum2 += b[y];
    		}
    		else {
    			x++;
    			sum1 += a[x];
    		}
    	}
    	
    	printf("%d\n", ans);
    		
    	
    
    	return 0;
    }
    
  • 相关阅读:
    NGINX原理分析 之 SLAB分配机制
    graphviz
    使用git Rebase让历史变得清晰
    An Implementation of Double-Array Trie
    转录组差异表达分析小实战(一)
    简单使用limma做差异分析
    简单使用DESeq2/EdgeR做差异分析
    简单使用DESeq做差异分析
    HISAT,sTRINGTIE,ballgown三款RNA-seq信息分析软件
    转录组的组装Stingtie和Cufflinks
  • 原文地址:https://www.cnblogs.com/komet/p/15879951.html
Copyright © 2020-2023  润新知