比賽連結:https://codeforces.com/contest/2039/problem/A
這次被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;
}
}
}