Codeforces Round 991 (Div. 3) \(A \sim G\)
- Codeforces Round 991 (Div. 3) \(A \sim G\)
- A
- 思路
- 程式碼
- B
- 思路
- 程式碼
- C
- 思路
- 程式碼
- D
- 思路
- 程式碼
- E
- 思路
- 程式碼
- F
- 思路
- 程式碼
- G
- 思路
- 程式碼
- A
Codeforces Round 991 (Div. 3)
補題, 不過 \(AK\)
廣告:starrycoding \(9\) 折優惠碼:
FV7B04LL
A
思路
列舉字串到剛好下一個字串無法塞入.
注意: 每次要把當前點測試用例讀完.
程式碼
void func(void)
{
int n,k;
cin >> n >> k;
string st;
int X = 0, ans = 0;
while(n --)
{
cin >> st;
if(X + st.size() <= k)
{
X += st.size();
ans ++;
}
else break;
}
while(n -- && n >= 0) cin >> st;
cout << ans << '\n';
}
B
思路
分析題意可得:
對於 \(i\), \(a_i-1\) 和 \(a_{i+1}\) 可以交換值;
對於 \(i+1\), \(a_i\) 和 \(a_{i+2}\) 可以交換值;
對於 \(i+2\), \(a_{i+1}\) 和 \(a_{i+3}\) 可以交換值;
所以: \(a_i,a_{i+2},a_{i+4}.\ldots\) 可以交換數值.
所以: 奇數位之間可以傳遞值, 偶數位可以傳遞值.
只需要判斷奇數(偶數)的值總和是否可以均分到每個數上,
且分配後奇偶位置數值相同, 則可行.
程式碼
#define ll long long
void func(void)
{
int n;
cin >> n;
vector<ll> a(n+1);
ll sum1 = 0,sum2 = 0,sum = 0;
for(int i=1;i<=n;++i)
{
cin >> a[i];
sum += a[i];
if(i&1) sum1 += a[i];
else sum2 += a[i];
}
int cnt1 = (n+1)/2, cnt2 = n/2;
if(sum % n == 0 && sum/n > 0 &&
sum1%cnt1 == 0 && sum1 / cnt1 > 0 &&
sum2%cnt2 == 0 && sum2 / cnt2 > 0 &&
sum1/cnt1 == sum2/cnt2)
{
cout << "YES\n";
}
else cout << "NO\n";
}
C
思路
\(9\) 的倍數的 數位之和 也為 \(9\) 的倍數.
分析可得, 只有\(2,3\) 可以進行一次平方, 且有意義.
在 \(\mod 9\) 意義下,
對於2:
- 一次平方使得總和 \(+(4-2 = 2)\).
- 多次相加, 結果為: \(\{2,4,6,8,1,3,5,7\}\), \(8\) 為週期.
對於3: - 一次平方使得總和 \(+(9-3 = 6)\).
- 多次相加, 結果為: \(\{6,3,0\}\), \(3\) 為週期.
- \(+0\) 無意義, 只需要考慮 \(2\) 次.
判斷在 \(\min(cnt_2,8)\) 次 \(+2\), 和 \(\min(cnt_3,2)\) 次 \(+6\) 任意組合下(最多 \(16種\)), 是否可以使得成為 \(9\) 的倍數.
程式碼
#define ll long long
void func(void)
{
string st;
cin >> st;
ll sum = 0;
int cnt2 = 0,cnt3 = 0;
for(auto &i : st)
{
sum += (i-'0');
if(i == '2') cnt2 ++;
if(i == '3') cnt3 ++;
}
int stp1 = min(cnt2,8), stp2 = min(cnt3,2);
for(int i=0;i<=stp1;++i)
{
for(int j=0;j<=stp2;++j)
{
if((i*2+j*6+sum) % 9ll == 0)
{
cout << "YES\n";
return ;
}
}
}
cout << "NO\n";
}
D
最開始沒考慮最多移動 \(10\) 次, 還準備上線段樹維護.
思路
對於第 \(i\) 個數, 最多向前移動 \(a_i \le 9\) 次
或者說, 第 \(i\) 個位置最多使用 \(i \sim i+9\) 十個位置.
那麼貪心這 \(10\) 個位置種的最大值(減去代價後)即可.
注意: 若是有相同大小的數, 使用哪個不影響結果, 因為他們位移到兩個位置的總代價相同.
程式碼
void func(void)
{
string st,ans;
cin >> st;
int len = st.size();
for(int i=0;i<len;++i)
{
int len2 = min(i+10,len);
int p = i;
for(int j=i;j<len2;++j)
{
if(st[j] - (j-i) > st[p]-(p-i)) p = j;
}
st[p] -= (p-i);
for(int j=p;j>i;--j) swap(st[j-1],st[j]);
}
cout << st << '\n';
}
E
思路
dp
\(dp\) 低手不太會解釋.
dp[i][op][k]
, op
表示是字串 \(a\)(0) 還是字串 \(b\)(1),
也就表示, 將 \(a[i]/b[i]\) 加入作為第 \(k\) 個字元後的最大值.
以 \(dp[i][0][k]\)個字元為例:
如果上一個字元也是 \(a\), 那麼只能從 \(dp[i-1][0][k-1]\) 轉移.
如果上一個字元是 \(b\), 需要從 \(dp[k-i][1][k-1]\) 轉移, 因為需要保證 \(i\) 前的 \(a\) 字元總數 \(+\) \(b\) 字元總數是 \(k-1\).
然後列舉 \(1\sim k\) 即可, 具體情況和注意事項看程式碼註釋.
程式碼
void func(void)
{
string a,b,c;
cin >> a >> b >> c;
int len1 = a.size(), len2 = b.size(), len = c.size();
a = '0' + a,b = '0' + b, c = '0' + c;// 保證下標從 1 開始
vector<vector<vector<int>>> dp(len+1,vector<vector<int>>(2,vector<int>(len+1)));
// 三位陣列, 和 int dp[len+1][2][len+1] 同理, 事實上第一維開 max(len1,len2)即可.
for(int k=1;k<=len;++k)
{
for(int i=max(1,k-len2);i<=min(k,len1);++i)
// 不能無腦從 1 開始, 因為如果 b 的所有字元數目都不足 k,
// 那麼必須從 a 種補足, 下一個迴圈同理.
{
dp[i][0][k] = max(dp[i-1][0][k-1],dp[k-i][1][k-1]) + (c[k] == a[i]);
}
for(int i=max(1,k-len1);i<=min(k,len2);++i)
{
dp[i][1][k] = max(dp[i-1][1][k-1],dp[k-i][0][k-1]) + (c[k] == b[i]);
}
}
int mx = 0;
for(int i=1;i<=len;++i) mx = max({mx,dp[i][0][len],dp[i][1][len]});
cout << len-mx << '\n';
}
F
線段樹!!!
(其實st表
就行).
思路
\(a \mod m = b \mod m\)
可得:
\(|a-b| \mod m = 0\).
那麼對於連續的序列
如 \(i,i+1,i+2\)
\(|a_i-a_{i+1}|\mod m_1 = 0\)
\(|a_{i+1}-a_{i+2}|\mod m_2 = 0\).
設 \(x\) 為 \(m\) 的因數, 那麼:
\(|a-b| \mod m = 0 \rightarrow |a-b| \mod x = 0\)
那麼對上述連續序列, 求 \(m_0 = \gcd(m_1,m_2)\) , \(m_0\) 即為 \(a_i,a_{i+1},a_{i+2}\), 的最大 \(m\).
所以用可以維護區間 \(\gcd\) 的容器維護即可.
線段樹
和st表
都可以
不會 st表
, 只有線段樹的了.
用線段樹維護連修改操作都不需要.
程式碼
st表
// 小秦提供
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define inf 0x3f3f3f3f
#define lc p<<1
#define rc p<<1|1
#define endl '\n'
#define all(a) a.begin()+1,a.end()
#define all0(a) a.begin(),a.end()
#define lowbit(a) (a&-a)
#define fi first
#define se second
#define pb push_back
#define yes cout<<"YES"<<endl
#define no cout<<"NO"<<endl
using namespace std;
const double eps=1e-6;
typedef pair<int,int>PII;
typedef array<int,3>PIII;
mt19937_64 rnd(time(0));
void solve()
{
int n,q;
cin>>n>>q;
vector<int>a(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
vector<vector<int>>f(n+1,vector<int>(20));
for(int i=1;i<n;i++) f[i][0]=abs(a[i+1]-a[i]);
for(int j=1;j<=20;j++)//列舉區間長度
{
for(int i=1;i+(1<<j)-1<=n;i++)//列舉起點
{
f[i][j]=__gcd(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
vector<int>nx(n+1);
nx[n]=n;
for(int i=n;i>=1;i--)
{
if(a[i]==a[i-1]) nx[i-1]=nx[i];
else nx[i-1]=i-1;
}
//for(int i=1;i<=n;i++) cout<<nx[i]<<endl;
auto query=[&](int l,int r)
{
r--;
int k=log2(r-l+1);
return __gcd(f[l][k],f[r-(1<<k)+1][k]);
};
while(q--)
{
int l,r;
cin>>l>>r;
if(nx[l]>=r) cout<<0<<" ";
else cout<<query(l,r)<<" ";
}
cout<<endl;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t;cin>>t;
while(t--)
solve();
return 0;
}
線段樹
#include<bits/stdc++.h>
#define Start cin.tie(0), cout.tie(0), ios::sync_with_stdio(false)
#define PII pair<int,int>
#define x first
#define y second
#define ull unsigned long long
#define int long long
using namespace std;
const int M = 1000000007;
const int N = 2e5 + 10;
int n,q;
vector<int> a(N),t(N<<2);
int gcd(int a,int b)
{
return (a == 0 ? b : gcd(b%a,a));
}
void build_tree(int be=1,int ed=n,int p=1)
{
t[p] = 0;
if(be == ed)
{
t[p] = a[be];
return ;
}
int mid = (be + ed) >> 1;
build_tree(be,mid,p<<1), build_tree(mid+1,ed,p<<1|1);
t[p] = gcd(t[p<<1],t[p<<1|1]);
}
int query(int l,int r,int be=1,int ed=n,int p=1)
{
if(l <= be && ed <= r) return t[p];
int mid = (be + ed) >> 1, res = 0;
if(l <= mid) res = gcd(res,query(l,r,be,mid,p<<1));
if(mid+1 <= r) res = gcd(res,query(l,r,mid+1,ed,p<<1|1));
return res ;
}
void func(void);
signed main(void)
{
Start;
int _ = 1;
cin >> _;
while(_--) func();
return 0;
}
void func(void)
{
cin >> n >> q;
vector<int> b(n+1);
for(int i=1;i<=n;++i) cin >> b[i];
n --;
for(int i=1;i<=n;++i) a[i] = abs(b[i] - b[i+1]);
if(n != 0) build_tree();
while(q--)
{
int l,r;
cin >> l >> r;
if(l == r) cout << 0 << ' ';
else cout << query(l,r-1) << ' ';
}
cout << '\n';
}
G
思路
樹上dp
真不會講了.
程式碼
#include<bits/stdc++.h>
#define Start cin.tie(0), cout.tie(0), ios::sync_with_stdio(false)
#define PII pair<int,int>
#define x first
#define y second
#define ull unsigned long long
#define int long long
using namespace std;
const int M = 1000000007;
const int N = 2e5 + 10;
int n,ans;
vector<int> a[N], dp(N);
void dfs(int p,int lp)
{
vector<int> X;
dp[p] = (int)a[p].size() - 2;
ans = max(ans,dp[p]+2);
for(auto &i : a[p])
{
if(i == lp) continue;
dfs(i,p);
X.push_back(dp[i]);
}
if(!X.size()) return ;
sort(X.begin(),X.end(),greater<int>());
dp[p] += X[0] > 0 ? X[0] : 0;
ans = max(ans,dp[p]+2);
if(X.size() >= 2) ans = max(ans,dp[p]+X[1]+2);
}
void func(void);
signed main(void)
{
Start;
int _ = 1;
cin >> _;
while(_--) func();
return 0;
}
void func(void)
{
ans = 0;
cin >> n;
for(int i=1;i<=n;++i) a[i].clear();
for(int i=1;i<n;++i)
{
int l,r;
cin >> l >> r;
a[l].push_back(r);
a[r].push_back(l);
}
dfs(1,0);
cout << ans << '\n';
}