Codeforces Round #635 div2 Solution

AA

b,c,cb,c,c一定能構成\triangle

int a,b,c,d,T;
int main() {
	qr(T); while(T--) {
		qr(a); qr(b); qr(c); qr(d);
		pr1(b); pr1(c); pr2(c);
	}
	return 0;
}

BB

暴力用操作1,再用操作2.

注意操作1不要增即可.

int T,x,n,m;

int main() {
	qr(T); while(T--) {
		qr(x); qr(n); qr(m);
		while(n&&x>(x/2)+10) n--,x=x/2+10;
		if(m*10>=x) puts("YES");
		else puts("NO");
	}
	return 0;
}

CC

最優情況下,一個點被設爲工業城市當且僅當子樹內所有點都爲工業城市.(微擾證明(交換))

所以用堆存depszdep-sz即可.

考試的時候想到了,但是不知道爲啥打掛了(WA#6)

priority_queue<int>q;
int n,m,fa[N],dep[N],sz[N];
ll ans;
struct edge{int y,next;}a[N<<1]; int len,last[N];
void ins(int x,int y) {a[++len]=(edge){y,last[x]};last[x]=len;}

void dfs(int x) {
	for(int k=last[x],y;k;k=a[k].next)
		if((y=a[k].y)^fa[x]) {
			fa[y]=x;
			dep[y]=dep[x]+1;
			dfs(y);
			sz[x]+=sz[y];
		}
	q.push(dep[x]-sz[x]);
	sz[x]++;
}

int main() {
	qr(n); qr(m); 
	for(int i=1,x,y;i<n;i++)
		qr(x),qr(y),ins(x,y),ins(y,x);
	dfs(1);
	while(m--) ans+=q.top(),q.pop();
	pr2(ans);	
	return 0;
}

DD

有點思維難度.

有個簡單性質.

對於確定的(x,y)(x,y),那麼zz(x+y)/2(x+y)/2越遠,總代價越大.

也就是我們取中間的決策優於取兩邊的決策.(決策包容性)

所以我們可以枚舉所有兩端爲(x,y),(x,z),(y,z)(x,y),(x,z),(y,z)的情況,然後用二分找到中間位置即可.

int T,a[N],b[N],c[N],n,m,q;
ull ans;

void upd(ll x,ll y,ll z) {
	ans=min(ans,(ull)(x-y)*(x-y)+(x-z)*(x-z)+(y-z)*(y-z));
}

int main() {
	a[0]=b[0]=c[0]=-1e9;
	qr(T); while(T--) {
		qr(n); qr(m); qr(q);
		for(int i=1;i<=n;i++) qr(a[i]);
		sort(a+1,a+n+1);
		for(int j=1;j<=m;j++) qr(b[j]);
		sort(b+1,b+m+1);
		for(int i=1;i<=q;i++) qr(c[i]);
		sort(c+1,c+q+1);
		a[n+1]=b[m+1]=c[q+1]=2e9;//注意邊界 
		ans=-1;
		int x=1,y=1;
		while(x<=n) {//x,y
			while(y<m&&b[y]<=a[x]) y++;
			for(int t=-1,*p;t<=0;t++)
				upd(a[x],b[y+t],*(p=lower_bound(c+1,c+q+2,(a[x]+b[y+t])/2))),
				upd(a[x],b[y+t],*(--p));
			x++;
		}
		x=y=1;
		while(x<=n) {//x,z
			while(y<q&&c[y]<=a[x]) y++;
			for(int t=-1,*p;t<=0;t++) 
				upd(a[x],c[y+t],*(p=lower_bound(b+1,b+m+2,(a[x]+c[y+t])/2))),
				upd(a[x],c[y+t],*(--p));
			x++;
		}
		x=y=1;
		while(x<=m) {//y,z
			while(y<q&&c[y]<=b[x]) y++;
			for(int t=-1,*p;t<=0;t++) 
				upd(b[x],c[y+t],*(p=lower_bound(a+1,a+n+2,(b[x]+c[y+t])/2))),
				upd(b[x],c[y+t],*(--p));
			x++;
		}
		pr2(ans);
	}
	return 0;
}

EE

考試的時候一眼看出要用O(n2)O(n^2)做,可是呢…

題目要求我們用ss的某個前綴通過操作得到一個前綴爲tt的字符串.(n=s,m=tn=|s|,m=|t|)

假設我們已經表達出了t[i..j]t[i..j],那麼如果[s[ji+2]=t[i1]][s[ji+2]=t[j+1]][s[j-i+2]=t[i-1]]\cup [s[j-i+2]=t[j+1]],就可表達出t[(i1)..j]t[i...(j+1)]t[(i-1)..j]或者t[i...(j+1)]

所以很明顯這是個區間dpdp.特別地,t[(m+1)..n]t[(m+1)..n]可以匹配任意字符.因爲我們只在乎t[1...m]t[1...m]完成匹配即可.

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3010,mod= 998244353;

void upd(int &x) {x-=mod; x+=x>>31&mod;}//x的合法範圍[0,2*mod)

int n,m,f[N][N],i,j,ans;
//f[i][j]表示t[i...j]由s[1...(j-i+1)]弄出的方案數.特別地,對於t[m]之後的字符可以匹配一切s中的字符.(我們只在乎前綴匹配) 
char s[N],t[N];

int main() {
	scanf("%s %s",s+1,t+1);
	n=strlen(s+1); 
	m=strlen(t+1);
	for(i=1;i<=m;i++) f[i][i]=(t[i]==s[1])*2;
	for(	;i<=n;i++) f[i][i]=2;
	for(i=2;i<=n;i++) {//枚舉長度
		for(j=1;j+i-1<=n;j++)
			upd(f[j][j+i-1]=f[j][j+i-2]*(j+i-1>m||t[j+i-1]==s[i])+f[j+1][j+i-1]*(j>m||t[j]==s[i]));
	}
	for(i=m;i<=n;i++) upd(ans+=f[1][i]);
	printf("%d\n",ans); return 0;
}

FF

如果2n2n次以上才判WA的話,那麼我應該可以在比賽時AC.

2n2n次操作的錯誤代碼:(想看就看吧)

int n,a[N],f[N];
ll l1,l2,n1,n2;

int main() {
	qr(n); scanf("%lld %lld",&l1,&l2);
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=2;j++) {
			printf("+ %d\n",i);
			fflush(stdout);
			scanf("%lld %lld",&n1,&n2);
		}
		a[i]=sqrt(n1-l1);
		l1=n1; l2=n2;
	}
	printf("! ");
	for(int i=1;i<n;i++) printf("%d ",a[i]);
	printf("%d",a[n]); fflush(stdout);
	return 0;
}

正解,EA的代碼

我們之所以需要2n2n次操作,是因爲我們沒有利用的straight tripletstraight ~triplet的條件.

觀察straight triplet(ST)straight ~triplet(ST)的變化:

如果有連續的5個數的出現次數a,b,c,d,ea,b,c,d,e

增加一個cc對應的數,則ΔST=ab+bd+de\Delta ST=ab+bd+de

所以如果我們已知b,c,d,eb,c,d,e那麼就可以用一次操作求aa了.

知道這個之後,我們的突破口就是就是把cc逼到角落(nn).使得參數變少,解出確定的值.

只需兩次操作,即可求得ana_n的具體值.然後我們嘗試推出前面的數.

因爲這次犧牲了兩次操作,我們自然想到把剩下的操作分配給[2,n1][2,n-1].(什麼鬼,哪自然了)

同時,假如最後取兩次nn的話,STST的值是相等的,我們是缺乏條件解出an1a_{n-1}的.

所以我們考慮設計最後三次爲n,n1,nn,n-1,n.

剩下的自己推一下吧~~

這題貌似:

思維難度:省選-

代碼難度:普及—

#include<cstdio>
using namespace std;
const int N=110;
int n,l1,l2,t[N],s[N],a,b,ans[N];
void q(int i,int &t,int &s) {
	printf("+ %d\n",i);
	fflush(stdout);
	scanf("%d %d",&t,&s);
	t-=l1; s-=l2;
	l1+=t; l2+=s;
}
int Sqrt(int x) {
	int i=1;
	while(i*i<=x) i++;
	return i-1;
}
int main() {
	scanf("%d %d %d",&n,&l1,&l2);
	for(int i=2;i<=n-2;i++) q(i,t[i],s[i]);
	q(n,t[n],s[n]); q(n-1,t[n-1],s[n-1]); q(n,a,b);
	ans[n]=Sqrt(a+t[n]);
	ans[n-2]=b-s[n]-1;
	ans[n-1]=s[n]/(ans[n-2]+1);
	ans[n-3]=s[n-1]/(ans[n-2]+1)-ans[n]-2;
	for(int i=n-4; i;i--)
		ans[i]=(s[i+2]-ans[i+3]*ans[i+4]-(ans[i+1]+1)*ans[i+3])/(ans[i+1]+1)-1;
	printf("! "); ans[1]++; for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0;
}

EA牛逼.

總結

這次比賽暴露出對貪心的生疏,和區間DP的不足,需要加強練習.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章