1. 程式人生 > 其它 >Codeforces Round #742 (Div. 2) ABCDE題解

Codeforces Round #742 (Div. 2) ABCDE題解

A 水題:直接'U'對應'D','D'對應'U',遇見LR複製一遍。

B 比較簡單:預處理300000內的xor字首異或,當xor[a-1]==b,直接0-->a即可。否則,如果xor[a-1]^b==a,那麼需要0-->a-1以及另外兩個數字xor得到a(避免直接用a)故a+1個數,如果xor[a-1]^b!=a,那麼0-->a-1以及xor[a-1]^b這a+2個數。

C題:發現對於奇數位和雙數位上的數相加,他們是分別並且獨立的。例如15678 , 那麼分離開168和57,我們發現只有分別滿足兩個數加和為168和57即可,那麼他們方案數相乘。最後要減去2,因為有(0,數)和(數,0)的情況。

點選檢視程式碼
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;

ll a[12],wz;
ll ans;
int main(){
	int t; scanf("%d",&t);
	while (t--) {
		ll n; wz = 0;
		scanf("%lld",&n);
		ans = 1;
		while (n) {
			a[++wz] = n%10;
			n/=10;
		}
		ll ad = 0; ll af = 0;
		for(int i=wz;i>=1;i-=2) {
			ad = ad*10ll + a[i];
		}
		for(int i=wz-1;i>=1;i-=2) {
			af = af*10ll + a[i];
		}
		ans = (ad+1)*(af+1)-2;
		printf("%lld\n",ans);
	}
	
	return 0;
}

D:其實就是一個模擬。。。我們發現只要拆分得儘可能不退位,退位先退低位就OK,程式碼寫得比較複雜。。

點選檢視程式碼
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>

using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
int S,N,wz;
int a[15],po[15];
int main(){
	po[1] = 1;
	for(int i=2;i<=10;i++) po[i] = po[i-1]*10;
	int t; scanf("%d",&t);
	while (t--) {
		wz = 0;
		scanf("%d%d",&S,&N);
		int sum = 0;
		while (S) {
			a[++wz] = S%10;
			S /= 10;
			sum += a[wz];
		}
		if(sum>=N) {
			int hb = sum-N+1;
			int ans = 0;
			for(int i=1;i<=wz&&hb;i++) {
				while(a[i]&&hb) {
					hb--; 
					ans += po[i]; 
					a[i]--;
				}
			}
            printf("%d ",ans); N--;
            for(int i=1;i<=wz;i++) {
                while(a[i]) {
                    printf("%d ",po[i]); a[i]--;
                }
            }
            puts("");
			continue;
		} else {
            for(int i=2;i<=wz;i++) {
				for(int j=1;j<=a[i];j++) q.push(po[i]);
			}
			while(q.size()+a[1]<N) {
				int x = q.top(); q.pop();
				if(x==10) a[1] += 10;
				else {
					for(int j=1;j<=10;j++) q.push(x/10);
				}
			}
			int ans = 0;
			while(a[1]&&a[1]+q.size()>N-1) {
				a[1]--; ans++; 
			}
			while(q.size()>N-1) {
				ans += q.top(); q.pop();
			}
			printf("%d ",ans);
			while(a[1]) {
				printf("1 "); a[1]--;
			}
			while(q.size()) {
				printf("%d ",q.top()); q.pop();
			}
			puts(""); continue;
		}
	}
	
	return 0;
}

發現一種驚為天人的寫法,還是太菜了(複製自xiaoziyao)

點選檢視程式碼
#include<stdio.h>
#include<math.h>
int T,n,m;
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<m;i++){
			int j=pow(10,(int)log10(n-(m-i)));
			printf("%d ",j),n-=j;
		}
		printf("%d\n",n);
	}
	return 0;
}

E:一道線段樹基本題吧,算是幫我徹徹底底地複習了一遍線段樹,也算是大有收穫吧。

本題開結構體記錄一段數列:1 字首連續最長不降 2 字尾連續最長不降 3 最左數 4 最右數 5該段包含答案對數 6該整段是否都是連續不降的

這樣轉移方式與維護方式就很簡單了,有點像小白逛公園。

點選檢視程式碼
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<bitset>
#include<queue>
#include<vector>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
const int maxn = 400005;
int n,q;
int a[maxn];
int tot,ls[maxn],rs[maxn],rt;

struct node {
	int lonpre,lonsuf,ln,rn;
	bool se;
	ll tt;
}z[maxn];

void init(int p,int x) {
	z[p].lonpre = z[p].lonsuf = z[p].se = z[p].tt = 1;
	z[p].ln = z[p].rn = a[x];
}
node operator+(node aa,node bb) {
	node cc;
	if(aa.se&&bb.se&&aa.rn<=bb.ln) cc.se = 1; else cc.se = 0;
	cc.lonpre = (aa.se&&aa.rn<=bb.ln) ? aa.lonpre + bb.lonpre : aa.lonpre;
	cc.lonsuf = (bb.se&&aa.rn<=bb.ln) ? bb.lonsuf + aa.lonsuf : bb.lonsuf;
	cc.tt = aa.tt + bb.tt + ( (aa.rn<=bb.ln) ? 1ll * aa.lonsuf * bb.lonpre : 0 ) ;
	cc.ln = aa.ln; cc.rn = bb.rn;
	return cc;
}
int maketree(int l,int r) {
	int p = ++tot;
	if(l==r) {
		init(p,l);
		return p;
	}
	int mid = (l+r)>>1;
	ls[p] = maketree(l,mid);
	rs[p] = maketree(mid+1,r);
	z[p] = z[ls[p]] + z[rs[p]];
	return p;
}
void update(int p,int l,int r,int x) {
	if(l==r) {
		init(p,l);
		return;
	}
	int mid = (l+r)>>1;
	
	if(x<=mid) update(ls[p],l,mid,x); 
	else update(rs[p],mid+1,r,x);
	z[p] = z[ls[p]] + z[rs[p]];
}
node query(int p,int l,int r,int x,int y) {
	if(x<=l&&r<=y) return z[p];
	int mid = (l+r)>>1;
	if(x>mid) return query(rs[p],mid+1,r,x,y);
	else if(y<=mid) return query(ls[p],l,mid,x,y);
	else return query(ls[p],l,mid,x,y) + query(rs[p],mid+1,r,x,y);
}
int main(){
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++) {
		scanf("%d",&a[i]);
	}
	rt = maketree(1,n);
	int ty,x,y;
	while(q--) {
		scanf("%d%d%d",&ty,&x,&y);
		if(ty==1) {
			a[x] = y;
			update(rt,1,n,x);
		} else {
			printf("%lld\n",query(rt,1,n,x,y).tt);
		}
	}
	 
	return 0;
}

F暫時待續吧。。。