CodeTON Round 9 (Div. 1 + Div. 2)

zhouruoheng發表於2024-11-25

CodeTON Round 9 (Div. 1 + Div. 2) 總結

A

自己推一下就能出來的,輸出奇數即可。

因為要遞增,所以儘可能取小的數字。

  • \(i=1\),餘數肯定是 \(0\),儘可能小,所以 \(a_1=1\)
  • \(i=2\),餘數儘可能小且不重,是 \(1\),所以 \(a_1=1+2=3\)
  • \(i=3\),餘數為 \(2\)\(a_3=2+3=5\)

這樣推導後知道 \(a_i=2 \times i+1\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=55;
int n;
void solve()
{
    cin>>n;
	for(int i=1;i<=n;i++) cout<<i*2-1<<' ';
    cout<<'\n';
}
int main ()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif 
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

B

肯定是往數量少的考慮。

\(f(t)\) 為偶數,以 \(t\) 的大小為依據分類討論。設 \(\lvert t\rvert\) 為字串 \(t\) 的大小。

  • \(\lvert t\rvert = 1\),顯然只有一個非空子串。
  • \(\lvert t\rvert = 2\)
    • 當兩個字元不同時,一定有三個子串,不符。
    • 當兩個字元相同時,會有兩個不同的子串,符合題意。
  • \(\lvert t\rvert = 3\)。只有三個字元都不同時,才會有 \(6\) 個不同的子串。

所以就是找連續的三個不同的字元或者兩個相同的字元。這樣思考一下,只有出現類似於 ababababa 這樣的字元才沒有子串符合條件。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=1e5+5;
string s;
void solve()
{
    cin>>s;
    int n=s.size();
    for(int i=0;i<n-2;i++)
        if(s[i]!=s[i+1]&&s[i]!=s[i+2]&&s[i+1]!=s[i+2])
        {
            cout<<s[i]<<s[i+1]<<s[i+2]<<'\n';
            return ;
        }
    for(int i=0;i<n-1;i++) 
        if(s[i]==s[i+1])
        {
            cout<<s[i]<<s[i+1]<<'\n';
            return ;
        }
    cout<<-1<<'\n';
}
int main ()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif 
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

C1

C 題都用到了一個性質,按位異或可以看作是不進位的加法。設 \(y>x\),就有 \(y \oplus x \in [y-x,y+x]\)

因此當 \(y>2x\) 時,\(y \oplus x > x\),因此 \(y \oplus x\) 不可能是 \(x\) 的因數。
\(y>2x\),也有 \(x < \frac{y}{2}\)\(y \oplus x > \frac{y}{2}\),又因為 \(x \ge 1\),所以 \(y \oplus x \neq y\) ,所以也不可能是 \(y\) 的因數。

所以 \(y \in [1,\min(2x,m)]\) 時才會產生貢獻。暴力列舉判斷即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=1;
int x;
ll m;
void solve()
{
    cin>>x>>m;
    ll n=1,cnt=0;
    while(n<=x) n<<=1;
    for(int y=1;y<=min(n-1,m);y++) 
    {
        int t=x^y;
        if(t==0) continue;
        if(x%t==0||y%t==0) cnt++;
    }
    cout<<cnt<<'\n';
}
int main ()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif 
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

C2

可以先打表找規律,發現小於 \(m\) 的幾乎所有 \(x\) 的倍數都滿足。

\(t=x \oplus y\),先考慮,\(t\)\(y\) 的倍數。
按位異或可以看作是不進位的加法,所以當 \(x<y\) 時,\(t<y+x=2y\),而因為 \(x \ge 1\)\(t \neq y\)\(y\) 的最小倍數為 \(2y\)。所有當 \(x<y\) 時,\(t\) 不可能是 \(y\) 的倍數。
所以只考慮 \(y \le x\)\(x\) 較小,暴力列舉 \(y\) 判斷即可。

再考慮 \(t\)\(x\) 的倍數。\(y=x\oplus t\),因為 \(x \oplus t \le x+t\),所以 \(x+t \le m\) 時,\(y \le m\)。所以 \(t \le m-x\)\(t\)\(x\) 的倍數時都符合題意。但要注意當 \(t=x\) 時,\(y=0\),該情況要捨去。還有因為 \(t=0\) 時,\(y=x\),這種情況會在考慮 \(t\)\(y\) 的倍數被計算,所有也沒有必要重複算。

\(t \oplus x \ge t-x\),若 \(t-x>m\),則有 \(y=t \oplus x>m\),不符。所以 \(t>m+x\) 時沒有貢獻。

還剩下一段區間為 \([m-x,m+x)\),最多產生兩個 \(x\) 的倍數,判斷一下 \(y\) 是否大於 \(x\) 且小於等於 \(m\) 即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=1;
ll x,m;

void solve()
{
    cin>>x>>m;
    ll ans=0,t;
	if(m>x)
	{
		ans+=max((m-x)/x-1,0ll);
		t=m/x*x;
		ll y=x^t;
		if(y>x&&y<=m) ans++;
		t+=x,y=x^t;
		if(y>x&&y<=m) ans++;
	}
    for(int y=1;y<=min(x,m);y++)
    {
        t=x^y;
        if(t%y==0) ans++;
    }
    cout<<ans<<'\n';
}
int main ()
{
    #ifndef ONLINE_JUDGE
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif 
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}

D

感覺上比 C2 簡單。

先轉變下條件,若 \(\gcd(i,j)=i\),即 \(i\)\(j\) 的因數,式子就變為 \(a_i \neq \gcd(a_i,a_j),1\le i < j \le n\),其中 \(j\)\(i\) 的倍數。

開始構造,將 \(s\) 從大到小排序。

  • \(i=1\),所以 \(2 \le j \le n\) 的所有 \(j\) 都有 \(a_i \neq \gcd(a_i,a_j)\),所以不妨讓 \(a_1\) 為最大,為 \(s_1\)。然後 \(2 \le j \le n\) 的所有 \(a_j\) 都不能是 \(s_1\)
  • \(i=2\),確定為 \(s_2\),能影響到 \(a_4,a_6,a_8,\dots\),這些都不能是 \(s_2\)
  • \(i=3\),可以為 \(s_2\),影響到 \(a_6,a_9,a_12,\dots\),這些不能是 \(s_2\)
  • \(a_4\) 可以為 \(s_3\)\(a_5\) 可以為 \(s_2\)\(a_6\) 可以為 \(s_3\)

就這麼推下去,找到 \(a_i\) 可以取的最大的 \(s_j\)。若超出 \(m\),就肯定無解。

列舉次數為 \(\frac{n}{1}+\frac{n}{2}+\frac{n}{3}+\dots+\frac{n}{n} \approx n\log(n)\),所以時間複雜度為 \(O(n\log(n))\)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>

using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,m;
int s[N],a[N];
bool cmp(int x,int y)
{
	return x>y;
}
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++) cin>>s[i];
	sort(s+1,s+m+1,cmp);
	for(int i=1;i<=n;i++) a[i]=0;
	a[1]=1;
	int mx=0;
	for(int i=1;i<=n;i++)
		for(int j=i*2;j<=n;j+=i)
		{
			a[j]=max(a[j],a[i]+1);
			mx=max(mx,a[j]);
		}
	if(mx>m)
	{
		cout<<-1<<'\n';
		return ;
	}
	for(int i=1;i<=n;i++) cout<<s[a[i]]<<' ';
	cout<<'\n';
}
int main ()
{
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	#endif 
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;
	cin>>T;
	while(T--) solve();
	return 0;
}

相關文章