1. 程式人生 > 其它 >Harbour.Space Scholarship Contest 2021-2022 (open for everyone, rated, Div. 1 + Div. 2)

Harbour.Space Scholarship Contest 2021-2022 (open for everyone, rated, Div. 1 + Div. 2)

A
容易發現只有進位的時候會出現這種情況。
所以直接輸出\(\frac{n+1}{10}\)即可。
code:

int T,n;
int main(){
	freopen("1.in","r",stdin);
	scanf("%d",&T);while(T--){
		scanf("%d",&n);printf("%d\n",(n+1)/10);[]
	}
}

B
暴力列舉兩個端點,然後折回去看能不能成立時間複雜度\(O(n^3)\)
但是其實可以hash做到\(O(n^2)\),大概是因為B題沒有加強。
code:

using namespace std;
int n,m,k,T;char s1[N+5],s2[N+5];
I int check(int l,int r){
	re int i;if(r*2-l<m||r-l+1>m) return 0;for(i=l;i<=r;i++) if(s1[i]^s2[i-l+1]) return 0;
	for(i=r-1;i>=r-(m-(r-l+1));i--) if(s1[i]^s2[r-i+r-l+1])return 0;return 1; 
}
I void solve(){
	re int i,j,h;scanf("%s",s1+1);scanf("%s",s2+1);n=strlen(s1+1);m=strlen(s2+1);
	for(i=1;i<=n;i++){
		for(j=i;j<=n;j++)if(check(i,j)){printf("YES\n");return;}
	}printf("NO\n");
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d",&T);while(T--)solve();
}

C
直接對每個問號爆搜然後取個min即可。
code:

using namespace std;
int T,fl[N+5],now1,now2,ans,n=10;char s[N+5];
I void calc(){
	re int i;now1=now2=0;for(i=1;i<=n;i++){
		if(i&1)now1+=(s[i]=='1');else now2+=(s[i]=='1');
		if((now1>now2&&(n-i+1)/2<now1-now2)||(now1<now2&&(n-i)/2<now2-now1)) {ans=min(ans,i);return;}
	}
}
I void dfs(int x){
	if(x==n+1) return calc();if(fl[x]) s[x]='0',dfs(x+1),s[x]='1',dfs(x+1);else dfs(x+1);
}
I void solve(){
	re int i;scanf("%s",s+1);for(i=1;i<=n;i++) fl[i]=(s[i]=='?');ans=10;dfs(1);printf("%d\n",ans);
}
int main(){
	freopen("1.in","r",stdin);
	scanf("%d",&T);while(T--) solve();
}

D
對起點是奇數起點還是偶數起點兩個都算一下即可。
注意要判是否在終點之後也是偶數,我就FST在這裡。
code:

int T,n,m,r,las,flag;char s1[N+5],s2[N+5];
I void solve(){
	re int i;scanf("%s%s",s1+1,s2+1);n=strlen(s1+1);m=strlen(s2+1);r=1;las=0;flag=0;
	for(i=1;i<=m;i++){
		while(r<=n&&(s1[r]^s2[i]||((r-las)%2==0))) r++;
		if(r==n+1)break;las=r;r+=(i!=m);
	}flag|=(r!=n+1&&(n-r+1)&1);
	r=las=1;for(i=1;i<=m;i++){
		while(r<=n&&(s1[r]^s2[i]||((r-las)%2==0))) r++;
		if(r==n+1)break;las=r;r+=(i!=m);
	}flag|=(r!=n+1&&(n-r+1)&1);
	puts(flag?"Yes":"No");
}
int main(){
	freopen("1.in","r",stdin);
	scanf("%d",&T);while(T--) solve();
}

E
沒看到\(m\leq \frac{n}{3}\)太日了。
可以發現我們最多換\(\frac{2n}{3}\)個位置所以有至少\(\frac{n}{3}\)個位置不動。
然後我們又知道一個點只在一個迴圈中不動。
所以答案不超過\(3\)
然後暴力數連通塊個數即可。
code:

int n,m,T,A[N+5],pl[N+5],F[N+5],cnt,Ans[N+5],fa[N+5],ToT,un,wn;
I int Getfa(int x){return x==fa[x]?x:fa[x]=Getfa(fa[x]);}
I void merge(int x,int y){
	un=Getfa(x);wn=Getfa(y);un^wn&&(fa[un]=wn,ToT--);
}
I void Solve(){
	re int i,j;for(i=0;i<=2*n;i++) F[i]=0;cnt=0;scanf("%d%d",&n,&m);for(i=1;i<=n;i++) scanf("%d",&A[i]),pl[A[i]]=i;
	for(i=1;i<=n;i++) pl[i+n]=pl[i];for(i=1;i<=n*2;i++) i>=pl[i]&&(F[i-pl[i]]++);
	for(i=0;i<n;i++){
		if(F[i]<n-2*m) continue;for(j=1;j<=n;j++) fa[j]=j;ToT=n;for(j=i+1;j<=i+n;j++) merge(j-i,pl[j]);
		n-ToT<=m&&(Ans[++cnt]=(n-i)%n);
	}sort(Ans+1,Ans+cnt+1);printf("%d ",cnt);for(i=1;i<=cnt;i++) printf("%d ",Ans[i]);puts("");
}
int main(){
	freopen("1.in","r",stdin);
	re int i;scanf("%d",&T);while(T--) Solve();
}

F
為什麼我的分塊和樹狀陣列一樣快啊。
首先我們考慮這個式子,其實要求\(G_{i-1}+\sum\limits_{j=1}^{i}{A_i\%A_j}+\sum\limits_{j=1}^{i}{A_j\%A_i}\)後面那個實在平凡暴力跳就好了反正調和級數\(O(nlogn)\),我們看前面那個。
拆成\(\sum\limits_{j=1}^{i}{A_i-A_j\times \lfloor \frac{A_i}{A_j}\rfloor}\)
後面那個直接整除分塊+樹狀陣列維護即可,時間複雜度\(O(n\sqrt wlog w)\)
然後觀察到我們有\(n\)次修改但是有\(n\sqrt w\)次查詢,所以按\(\sqrt w\)分塊就可以\(O(n\sqrt w)\)了。
但是他們兩個跑得一樣快……
code:

int n,k,x,y,z,Maxn;ll G[N+5],ToT,A[N+5],F[N+5];
struct Tree{
	ll F[N+5],Q[N+5];
	I void get(int x,int y){re int i;for(i=x;i<x/k*k+k;i++)F[i]+=y;for(i=x/k+1;i<=Maxn/k;i++)Q[i]+=y;}
	I ll find(int x,int y){return (F[y]+Q[y/k])-(F[x-1]+Q[(x-1)/k]);}
}S1,S2; 
I ll calc1(int m){
	re int i,j;ll Ans=0;for(i=1;i<=m;i=j+1)j=m/(m/i),Ans+=1ll*(m/i)*S1.find(i,j);return Ans;
}
I ll calc2(int m){
	re int i,j;ll Ans=0;for(i=0;i<=Maxn;i+=m){
		Ans+=1ll*(i/m)*m*S2.find(i,min(i+m-1,Maxn)); 
	}return Ans;
}
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	re int i;scanf("%d",&n);k=sqrt(n);for(i=1;i<=n;i++) scanf("%lld",&A[i]),Maxn=max(Maxn,A[i]);
	for(i=1;i<=n;i++){
		G[i]=A[i]*(i-1)+ToT;G[i]-=calc1(A[i])+calc2(A[i]);//printf("%lld %lld\n",calc1(A[i]),calc2(A[i]));
		G[i]+=G[i-1];S1.get(A[i],A[i]);S2.get(A[i],1);ToT+=A[i];printf("%lld ",G[i]);	
	}
}

GHI咕咕咕