CodeTON Round 9 (Div. 1 + Div. 2, Rated, Prizes!)题解记录(A~D,附带E规律公式)

比赛链接:https://codeforces.com/contest/2039
这次被C2卡了两个小时,D题最后提前一分钟AC,有点刺激。感觉做了些难题,但是rating没加多少,看来得避免和红名和橙名同台竞技。下次div1+div2就不打了,等两周后打打div2?正好得准备期末考试了。

A. Shohag Loves Mod

题面:
Shohag 有一个整数 $ n $。请帮助他找到一个递增的整数序列 $1 \le a_1 < a_2 < \ldots < a_n \le 100 $,使得对于所有的 $1 \le i < j \le n $ 都满足 $a_i \bmod i \neq a_j \bmod j $。

它表明,在给定的约束下,这样的序列总是存在的。

$^{\ast} $ $a \bmod b $ 表示 $a $除以 $b $后的余数。例如, $7 \bmod 3 = 1 $, $8 \bmod 4 = 0 $ 和 $69 \bmod 10 = 9 $。
输入:
第一行包含一个整数 $t $(\(1 \le t \le 50\))——测试用例的数量。

每个测试用例的唯一一行包含一个整数 $n $(\(2 \le n \le 50\))。
输出:
对于每个测试用例,打印一个满足题目中提到的条件的非空字符串,或者如果没有这样的字符串存在,则打印 $-1 $。如果有多个解决方案,请输出任意一个。
样例:
2
3
6
——————
2 7 8
2 3 32 35 69 95
思路:主要是得找到最短符合答案,不然包被hack得。发现第一个数可以为2,于是选了2,然后第2个数可以为3且3%2==1,不等于0,可以!。然后4不可以,5可以,这样浅浅枚举下,2以后,输出3,5,7这种等差数列即可,所以其实可以写成2*i-1的

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<stdio.h>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                         long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll maxn = 5e5+5;
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll ksm(ll x,ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
		ans=ans%mod*(x%mod)%mod;
		x=x%mod*(x%mod)%mod;
		y>>=1;
	}
	return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
	if(y==0)
	return x;
	else 
	return gcd(y,x%y);
}
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll n;
		cin>>n;
		if(n>0)
		cout<<2<<" ",n--;
		for(ll i=3;i<=100;i+=2)
		{
			if(n==0)
			break;
			n--;
			cout<<i<<" ";
		}
		cout<<endl;
	}
}

B. Shohag Loves Strings

题面:
对于一个字符串 $ p $,让 $ f(p) $表示 $ p $ 的不同非空子串的数量。

Shohag 有一个字符串 $ s $。帮助他找到一个非空字符串 \(p\),使得$ p $ 是 $ s $的一个子串,并且 \(f(p)\) 是偶数,或者声明没有这样的字符串存在。

\(^{\ast}\) 如果可以通过从 $ b $ 中删除一些(可能为零个或全部)字符从开头和一些(可能为零个或全部)字符从末尾来获得 $ a $,则称字符串 $ a $ 是字符串 $ b$ 的一个子串。
输入:

第一行包含一个整数 $ t $(\(1 \le t \le 10^4\))——测试用例的数量。

每个测试用例的唯一一行包含一个字符串 $ s $(\(1 \le |s| \le 10^5\)),由小写英文字母组成。

保证所有测试用例中 $ s $ 的长度之和不超过$3 \cdot 10^5 $。
输出:
对于每个测试用例,打印一个满足题目中提到的条件的非空字符串,或者如果没有这样的字符串存在,则打印 \(-1\)。如果有多个解决方案,请输出任意一个。
样例:
5
dcabaac
a
youknowwho
codeforces
bangladesh


abaa
-1
youknowwho
eforce
bang
思路:其实枚举下,形如abc,aa,abcd都是可以的。所以特判长度为1或2,然后先检测有没相邻两个相同的,有就输出答案,没有就检测有没有f[i]!=f[i+2]且由三个字符构成的串,由就输出答案,没有就只能输出-1.不会有人不会substr吧。

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<stdio.h>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                         long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll maxn = 5e5+5;
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll ksm(ll x,ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
		ans=ans%mod*(x%mod)%mod;
		x=x%mod*(x%mod)%mod;
		y>>=1;
	}
	return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
	if(y==0)
	return x;
	else 
	return gcd(y,x%y);
}
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		string f;
		cin>>f;
		if(f.size()==1)
		cout<<-1<<endl;
		else if(f.size()==2)
		{
			if(f[0]==f[1])
			cout<<f<<endl;
			else 
			cout<<-1<<endl;
		}
		else 
		{
			ll pd=0;
			string c;
			for(ll i=0;i<f.size()-1;i++)
			{
				if(f[i]==f[i+1]&&pd==0)
				{
					c=f.substr(i,2);
					pd=1;
				}
			}
			for(ll i=0;i<f.size()-1;i++)
			{
				if(i+2<=f.size()-1&&pd==0&&f[i]!=f[i+2])
				{
					c=f.substr(i,3);
					pd=1;
				}
			}
			if(pd)
			cout<<c<<endl;
			else cout<<-1<<endl;
		}
	}
}

C1. Shohag Loves XOR (Easy Version)

题面:
这是问题的简单版本。两个版本之间的差异用粗体标出。只有在解决了问题的两个版本后,你才能进行hack。

Shohag有两个整数 $ x $ 和 $ m $。帮助他计算满足 $1 \le y \le m $且 $ \mathbf{x \neq y} $并且 \(x\) \(\oplus\) \(y\)一个因数\(^{\text{∗}}\)\(x\)\(y\) 或两者的整数数量。这里 \(\oplus\)位异或运算符。

\(^{\text{∗}}\) 如果存在一个整数 $ c $ 使得 $a = b \cdot c $,则称数字 $ b $ 是数字 $ a $ 的一个因数。
输入:

第一行包含一个整数 $ t $(\(1 \le t \le 10^4\))——测试用例的数量。

每个测试用例的唯一一行包含两个用空格分隔的整数 \(x\)和 $ m$(\(1 \le x \le 10^6\)\(1 \le m \le 10^{18}\))。

保证所有测试用例中 $ x $ 的总和不超过 $10^7 $。
输出:
对于每个测试用例,打印一个整数——合适的 $ y $ 的数量。
样例:
5
6 9
5 7
2 3
6 4
4 1


3
2
1
1
0
思路:这题真的不难,送分的。显然\(x\) \(\oplus\) \(y\)得是x或y的因数,那首先肯定要比x或着y小,而知道如果两个数的最大二进制位相同,则两者一定不会出现一个数是另一个因数的情况。这样就可以很好解决了,我就只考虑到比x大一点就好了,所以直接求出比x的二进制大一位的位置的数字然后减1,再和m取个min枚举就好了,这样直接枚举不超过x的2倍,而x总数小于等于1e7,枚举不会TLE,记得特判同位置不可算就好了

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<stdio.h>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                         long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll maxn = 5e5+5;
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll ksm(ll x,ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
		ans=ans%mod*(x%mod)%mod;
		x=x%mod*(x%mod)%mod;
		y>>=1;
	}
	return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
	if(y==0)
	return x;
	else 
	return gcd(y,x%y);
}
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll x,m;
		cin>>x>>m;
		ll pd=0;
		for(ll i=0;i<=60;i++)
		{
			if(x&(1ll<<i))
			{
				pd=i;
			}	
		}
		ll u=min(m,(1ll<<(pd+1))-1);
		ll ans=0;
		for(ll i=1;i<=u;i++)
		{
			ll j=(x^i);
			if(j==0)continue;
			if(x%j==0||i%j==0)
			ans++;
		}
		cout<<ans<<endl;
	}
}

C2. Shohag Loves XOR (Hard Version)

题面:
这是问题的困难版本。两个版本之间的差异用粗体标出。只有在解决了问题的两个版本后,你才能进行hack。

Shohag有两个整数 \(x\)\(m\)。帮助他计算满足 $ 1 \le y \le m$的整数数量,使得 \(x\) \(\oplus\) \(y\)能被整除\(^{\text{∗}}\)\(x\)\(y\) 或两者。这里 \(\oplus\)位异或运算符。
\(^{\text{∗}}\)如果存在一个整数 $c $使得 $ a = b \cdot c $,则称数字 \(a\) 能被数字 \(b\) 整除。
输入:

第一行包含一个整数 $ t $(\(1 \le t \le 10^4\))——测试用例的数量。

每个测试用例的唯一一行包含两个用空格分隔的整数 \(x\)\(m\)\(1 \le x \le 10^6\)\(1 \le m \le 10^{18}\))。

保证所有测试用例中 $ x $ 的总和不超过 $ 10^7 $。
输出:
对于每个测试用例,打印一个整数——合适的 $ y $ 的数量。
样例:
5
7 10
2 3
6 4
1 6
4 1
————————
3
2
2
6
1
思路:真的好吃😋,这道题卡了我快2个小时!!!!做不出来不要死磕着啊
好在第二小时左右过了,这里主要是得想办法把\(x\) \(\oplus\) \(y\)区间化,首先x及以下的我可以暴力先求出来,这里先把x的涉及的二进制区先枚举完,然后得再枚举一个二进制大一点得2的次幂减1,这样子就可以保证这个数是区间左端(这里得看有没有超过m,超过了就直接枚举到m输出即可),然后现在考虑区间右端,发现如果\(x\) \(\oplus\) \(m\)后最大值不能确定啊?所以这时候得直接对m进行二进制扫描,如果对应二进制存在且大于等于x就继续扫,直到扫不动,这里扫到得2的次幂得加起来,然后暴力枚举m到这个数(这里得判断有没有小于区间左端),随后扫到的数-1就为右端点,直接再加右端点除以x-左端点除以x即可得到答案。
这里证明下正确性,显然对于二进制1011111,其异或二进制1011,如果枚举0~1011111所对应的数,一定会把区间所有可能的数异或出来,且最大值一定为1011111所对应的数。

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<stdio.h>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                         long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll maxn = 5e5+5;
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll ksm(ll x,ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
		ans=ans%mod*(x%mod)%mod;
		x=x%mod*(x%mod)%mod;
		y>>=1;
	}
	return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
	if(y==0)
	return x;
	else 
	return gcd(y,x%y);
}
ll ck(ll x,ll m)
{
	ll cnt=0;
	for(ll i=1;i<=m;i++)
	{
		ll u=(i^x);
		if(u%i==0||u%x==0)
		cnt++;
	}
	return cnt;
}
int main()
{
	fio();
	ll t;
	cin>>t;
	while(t--)
	{
		ll x,m;
		cin>>x>>m;
		if(x==1)
		{
		cout<<m<<endl;
		continue;
		}
		ll pd=0;
		for(ll i=0;i<=60;i++)
		{
			if(x&(1ll<<i))
			{
				pd=i;
			}
		}
		ll u=min(m,(1ll<<(pd+1))-1);
		ll ans=0;
		ll op=0;
		ll jo=0;
			for(ll i=1;i<=u;i++)
			{
				ll k=(x^i);
				if(k%x==0||k%i==0)
				ans++;
			}
		if((1ll<<pd+2)-1>=m)
		{
			for(ll k=(1ll<<pd+1);k<=m;k++)
			{
				ll f=(x^k);
				if(f%x==0||f%k==0)
				ans++;
			}
			cout<<ans<<endl;
			continue;
		}
		else 
		{
			for(ll k=(1ll<<pd+2)-1;k>=(1ll<<pd+1);k--)
			{
					ll f=(x^k);
					if(f%x==0||f%k==0)
				      ans++;
			}
			op=(1ll<<pd+2)-1;
		}
		if(u!=m)
		{
			ll cs=op/x;
			ll cnt=0;
			ll ko=0;
			ll pd=0;
			ll h=0;
		for(ll i=60;i>=0;i--)
		{
			if(m&(1ll<<i)&&cnt==0)
			{
				cnt=1;
				ko+=(1ll<<i);
			}
			else if(m&(1ll<<i)&&cnt==1)
			{
				if((1ll<<i)>=x)
				ko+=(1ll<<i),h=i;
			}
		}
		ll d=max(ko,op+1);
		for(ll j=m;j>=d;j--)
		{
			ll u=(j^x);
			if(u%x==0||u%j==0)
			ans++;
		}
		if(d!=op+1)
		{
		ko-=(1ll<<h);
		ko+=(1ll<<h)-1;
		ans+=ko/x-op/x;
		}
		cout<<ans<<endl;
		//cout<<ck(x,m)<<endl;
	}
}
}

D. Shohag Loves GCD

题面:
Shohag 有一个整数 \(n\) 和一个包含 \(m\) 个唯一整数的集合 \(S\)。帮助他找到一个字典序最大的整数数组 \(a_1, a_2, \ldots, a_n\),使得对于每个 \(1 \le i \le n\),都有 \(a_i \in S\),并且对于所有 \(1 \le i < j \le n\),都满足 \(a_{\gcd(i, j)} \neq \gcd(a_i, a_j)\),或者声明不存在这样的数组。

\(^{\ast}\) 如果数组 \(a\) 和相同长度的数组 \(b\) 不相等,并且在 \(a\)\(b\) 不同的第一个位置,数组 \(a\) 的元素比 \(b\) 中对应的元素大,则称数组 \(a\) 字典序大于数组 \(b\)

\(^{\dagger}\) \(\gcd(x, y)\) 表示整数 \(x\)\(y\)最大公约数 (GCD)
输入:
第一行包含一个整数 \(t\)\(1 \le t \le 10^4\))——测试用例的数量。

每个测试用例的第一行包含两个整数 \(n\)\(m\)\(1 \le m \le n \le 10^5\))。

每个测试用例的第二行包含 \(m\) 个唯一整数,按递增顺序排列,代表集合 \(S\) 的元素(对于每个 \(x \in S\),有 \(1 \le x \le n\))。

保证所有测试用例中 \(n\) 的总和不超过 \(3 \cdot 10^5\)
输出:
对于每个测试用例,如果没有解决方案,请打印 \(-1\),否则打印 \(n\) 个整数——满足条件的字典序最大的整数数组。
样例:
3
6 3
3 4 6
1 1
1
2 1
2
————————
6 4 4 3 4 3
1
-1
思路:虽然没C2好吃,但是也是快结束才交,早在2.30就交了发,WA6了,想了会才发现错误点.要字典序最大,所以第一个肯定得放最大的数,由题目 \(a_{\gcd(i, j)} \neq \gcd(a_i, a_j)\),可得,对于1以外的数都不能等于这个数了,所以第一个数固定。对于第二个数,得放得尽可能多的位置,所以对于每个为质数的位置,我都放第二大的数。好了现在考虑第三大的数,选择目前能选的最小位置的数,然后暴力计标记一遍其所有倍数,然后继续遍历,遍历到没标记的重复之前的操作。随后再用vector解标记,删位置,后面都重复此类似操作就行了。我之所以WA6,是因为第三次及以后只考虑了第一个数的倍数,后面都没考虑,想了下此时,18,30就是我的反例,因为他们不满足\(a_{\gcd(i, j)} \neq \gcd(a_i, a_j)\)

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<stdio.h>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                         long long 
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll maxn = 5e5+5;
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll ksm(ll x,ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1)
		ans=ans%mod*(x%mod)%mod;
		x=x%mod*(x%mod)%mod;
		y>>=1;
	}
	return ans%mod%mod;
}
ll gcd(ll x,ll y)
{
	if(y==0)
	return x;
	else 
	return gcd(y,x%y);
}
ll ck(ll x,ll m)
{
	ll cnt=0;
	for(ll i=1;i<=m;i++)
	{
		ll u=(i^x);
		if(u%i==0||u%x==0)
		cnt++;
	}
	return cnt;
}
ll a[150000];
ll b[150000];
bool st[150000];
ll d[150000];
bool c[150000];
ll gs=0;
void ola(ll x)
{
	for(ll i=2;i<=x;i++)
	{
		if(st[i]==0)gs++,d[gs]=i,c[i]=1;
		for(ll j=1;d[j]<=x/i;j++)
		{
			st[i*d[j]]=1;
			if(i%d[j]==0)
			break;
		}
	}
}
ll vis[150000];
set<ll>g;
vector<ll>ok;
vector<ll>fo;
int main()
{
	fio();
	ll t;
	cin>>t;
	ola(100000);
	while(t--)
	{
		g.clear();
		ok.clear();
		fo.clear();
		ll n,m;
		cin>>n>>m;
		for(ll i=1;i<=m;i++)
		cin>>a[i];
		ll u=m;
		for(ll i=1;i<=n;i++)
		{
			vis[i]=0;
			g.insert(i);
		}
		for(ll k=m;k>=1;k--)
		{
		if(k==m)
		{
			ll d=0;
		for(auto j:g)
		{
			b[j]=a[m];
			d=j;
			break;
		}
		g.erase(d);
		}
		else if(k==m-1)
		{
			ok.clear();
			for(auto j:g)
			{
				if(c[j])
				{
					b[j]=a[k];
					ok.push_back(j);
				}
			}
			for(auto j:ok)
			{
				g.erase(j);
			}
		}
		else 
		{
			ok.clear();
			fo.clear();
			ll u=0;
			for(auto j:g)
			{
				if(vis[j])continue;
				if(u==0)
				u=j,b[j]=a[k],ok.push_back(j);
				else
				{ 
				u=j;
				b[j]=a[k];
				ok.push_back(j);
				}
				for(ll z=1;z*j<=n;z++)
				{
					if(vis[z*j])continue;
					vis[z*j]=1;
					fo.push_back(z*j);
				}
			}
			for(auto j:fo)vis[j]=0;
			for(auto j:ok)
			{
				g.erase(j);
			}
		}
		}
		if(g.size()>0)
		cout<<-1<<endl;
		else 
		{
		for(ll j=1;j<=n;j++)
		cout<<b[j]<<" ";
		cout<<endl;
		}
    }
}

E. Shohag Loves Inversions

题面:
Shohag 有一个整数数组 a。最初 a = [0, 1]。他可以重复执行以下操作任意次数:

  • k 为当前数组 a 中的反转数∗。
  • a 中的任何位置插入 k,包括开头或结尾。

例如,如果 a = [4, 6, 2, 4],则反转数为 k = 3。所以 Shohag 在操作后可以得到以下数组:[3, 4, 6, 2, 4][4, 3, 6, 2, 4][4, 6, 3, 2, 4][4, 6, 2, 3, 4][4, 6, 2, 4, 3]

给定一个整数 n,帮助 Shohag 计算,模数 998244353,执行操作后可以获得的不同长度 n 数组的数量。

∗ 数组 a 中反转数是索引对 (i, j) 的个数,使得 i < j\(a_i\) > \(a_j\)
输入:

  • 第一行包含一个整数 \(t\)\(1 \leq t \leq 10^4\))——测试用例的数量。
  • 每个测试用例的第一行也是唯一一行包含一个整数 \(n\)\(2 \leq n \leq 10^6\))。

保证所有测试用例的 \(n\) 之和不超过 \(10^6\)
输出:
对于每个测试用例,输出一个整数 — 可能的数组数模 \(998244353\)
样例:
4
4
2
7
69
——————
5
1
682
325188814
公式版:
思路:本题正解为dp,这里给出评论区看到的大佬推的公式(orz,请看代码),dp日后补充

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<stack>
#include<string>
#define ll                                     long long
#define lowbit(x) (x & -x)
#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
const ll p=rnd()%mod;
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll a[1000002];
int main()
{
	fio();
	a[2]=1,a[3]=2,a[4]=5,a[5]=19;
	for(ll i=2;i<=1000000-2;i++)
	{
		a[i+2]=((a[i+1]%mod*(i+3)%mod)%mod-(a[i]%mod*((i+2)%mod))%mod-1)%mod;
		a[i+2]+=1000*mod;
		a[i+2]%=mod;
	}
	ll t;
	cin>>t;
	while(t--)
	{
		ll n;
		cin>>n;
		cout<<a[n]<<endl;
	}
}
posted @ 2024-11-24 02:50  长皆  阅读(306)  评论(0编辑  收藏  举报