链接:
2024 ICPC Asia Chengdu Regional Contest (The 3rd Universal Cup. Stage 15: Chengdu)
A:Arrow a Row
大意:
思路:
先判断不能的,长度小于5或者第一个跟最后三个不是箭头的都不能,还有就是没有横线的也不能。
其他都是能的,现在就看怎么构造,直接先第一个和最后一堆箭头,然后中间的的和最后一堆箭头的前三个,注意顺序,要不箭头就会被覆盖。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
string s;cin >> s;
int n = s.size();
s = '!' + s;
if (n < 5)
{
cout << "No" << endl;
return;
}
bool flag = false;
for (int i = 1; i <= n; i++){
if (s[i] == '-'){
flag = true;
break;
}
}
int d[] = { 1, n - 2, n - 1, n };
for (int i = 0; i < 4; i++)
if (s[d[i]] != '>')flag = false;
if (!flag)
{
cout << "No" << endl;
return;
}
vector<pair<int, int>> v;
int i;
for (i = n - 2; i > 1; i--)
if (s[i] == '>')v.push_back({ 1, i + 2 });
else break;
for (int j = 2; j < i; j++)
if (s[j] == '>')v.push_back({ j, i + 3 - j + 1 });
int num = v.size();
cout << "Yes " << num << endl;
for (int i = 0; i < num; i++)
cout << v[i].ff << ' ' << v[i].ss << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
B:Athlete Welcome Ceremony
大意:
思路:
dp + 三维前缀和
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
int dp[310][310][310][3]; // ijkz 对前i个字符,使用了j个a字符,k个b字符,第i个字符是 z + 'a'的方案数
int f[310][310][310]; // 有i个a,j个b,k个c的方案数
void solve()
{
int n, m;
cin >> n >> m;
string s;cin >> s;
s = ' ' + s;
vector<int> cnt(n + 1);
for (int i = 1; i <= n; i++)cnt[i] = cnt[i - 1] + (s[i] == '?');
// 先初始化一下方案数
if (s[1] == '?')
dp[1][1][0][0] = dp[1][0][1][1] = dp[1][0][0][2] = 1;
else
dp[1][0][0][s[1] - 'a'] = 1;
for (int i = 2; i <= n; i++)
{
for (int ca = 0; ca <= cnt[i]; ca++)
{
for (int cb = 0; cb + ca <= cnt[i]; cb++)
{
if (s[i] != '?')
{
int num = dp[i - 1][ca][cb][0] + dp[i - 1][ca][cb][1] + dp[i - 1][ca][cb][2]; //上一层总方案数
dp[i][ca][cb][s[i] - 'a'] = (num - dp[i - 1][ca][cb][s[i] - 'a']) % mod; // 去掉上一层一样的,其他结尾字母为0
continue;
}
if (ca)
{
int num = dp[i - 1][ca - 1][cb][1] + dp[i - 1][ca - 1][cb][2];
dp[i][ca][cb][0] = num % mod;
}
if (cb)
{
int num = dp[i - 1][ca][cb - 1][0] + dp[i - 1][ca][cb - 1][2];
dp[i][ca][cb][1] = num % mod;
}
if (cnt[i] - ca - cb)
{
int num = dp[i - 1][ca][cb][0] + dp[i - 1][ca][cb][1];
dp[i][ca][cb][2] = num % mod;
}
}
}
}
// 先获得特定i j k对应的方案数
for(int i = 0; i <= cnt[n]; i ++)
for (int j = 0; i + j <= cnt[n]; j++)
{
int num = dp[n][i][j][0] + dp[n][i][j][1] + dp[n][i][j][2];
f[i][j][cnt[n] - i - j] = num % mod;
}
// 获得i j k有富余的情况对应的方案数 三维前缀和
for (int i = 0; i <= 300; i++) {
for (int j = 0; j <= 300; j++) {
for (int k = 0; k <= 300; k++) {
if (i > 0) f[i][j][k] += f[i - 1][j][k];
if (j > 0) f[i][j][k] += f[i][j - 1][k];
if (k > 0) f[i][j][k] += f[i][j][k - 1];
if (i && j)f[i][j][k] += mod - f[i - 1][j - 1][k];
if (k && j)f[i][j][k] += mod - f[i][j - 1][k - 1];
if (i && k)f[i][j][k] += mod - f[i - 1][j][k - 1];
if (i && j && k)f[i][j][k] += f[i - 1][j - 1][k - 1];
f[i][j][k] %= mod;
}
}
}
while (m --)
{
int x, y, z; cin >> x >> y >> z;
cout << f[x][y][z] << '\n';
}
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
//cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
G:Expanding Array
大意:
思路:
这里我的思考流程是:
1、先发现两个数操作可以转换成两个数无限操作
2、再发现对于x的某位,y的对应位,
x = 1,y = 1
x = 1, y = 0
x = 0, y = 1
x = 0, y = 0
每个位都对应以上一种情况,进行操作时,这些位属于同一类的会发生相同的变化,那么最后的结果就是这四类的自由组合,放到set 里面去重就行
下面是官方题解:
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n;cin >> n;
vi a(n + 1);
for (int i = 1; i <= n; i++)cin >> a[i];
set<int>S;
S.insert(0);
for (int i = 2; i <= n; i++)
{
int n11 = 0, n10 = 0, n01 = 0;
for (int j = 31; j >= 0; j--)
{
int n1 = a[i - 1] & (1LL << j);
int n2 = a[i] & (1LL << j);
if (n1 && n2)n11 |= n1;
else if (n1)n10 |= n1;
else if (n2)n01 |= n2;
}
vi v = { n11, n10, n01, n11 + n10, n11 + n01, n10 + n01, n11 + n01 + n10 };
for (auto it : v)S.insert(it);
}
cout << S.size() << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
//cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
I:Good Partitions
大意:
思路:
为什么求gcd可以用断点i?,因为(a, b, c) = (a, b - a, c - b),正好为区间长度
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
int cnt[N];
int n, m;
struct node
{
int l, r, d;
}tr[N << 2];
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
void pushup(int u)
{
tr[u].d = gcd(tr[u << 1].d, tr[u << 1 | 1].d);
}
void build(int u, int l, int r)
{
tr[u] = { l, r, 0 };
if (l != r)
{
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
}
void modify(int u, int x, int v)
{
if (tr[u].l == tr[u].r)tr[u].d = v;
else
{
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid)modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
void solve()
{
cin >> n >> m;
build(1, 1, n);
vector<int> a(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i < n; i++)
{
if (a[i] > a[i + 1])modify(1, i, i);
else modify(1, i, 0);
}
int ans = tr[1].d;
if (ans == 0)cout << n << endl; // 每次都要特判全零
else cout << cnt[ans] << endl; // 答案就为最大公约数的约数个数
int p, v;
while (m--)
{
cin >> p >> v;
a[p] = v;
// 修改一个点,影响前向差分和后向差分
if (a[p - 1] > a[p])modify(1, p - 1, p - 1);
else modify(1, p - 1, 0);
if (p < n)
{
if (a[p] > a[p + 1])modify(1, p, p);
else modify(1, p, 0);
}
int ans = tr[1].d;
if (ans == 0)cout << n << endl;
else cout << cnt[ans] << endl;
}
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
for (int i = 1; i <= 200001; i++)
for (int j = 1; j * i <= 200001; j++)
cnt[i * j] ++;
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
J:Grand Prix of Ballance
大意:
思路:
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int n, m, q;cin >> n >> m >> q;
map<int, bool>st;
vi v(m + 1);
int con = -1;
int score = m;
while (q --)
{
int op;cin >> op;
if (op == 1)
{
cin >> con;
st.clear();
score = m;
}
if (op == 2)
{
int x, y;cin >> x >> y;
if (y != con || st[x])continue;
st[x] = true;
v[x] += score --;
}
if (op == 3)
{
int x, y;cin >> x >> y;
if (y != con || st[x])continue;
st[x] = true;
}
}
vi p(m + 1);
for (int i = 1; i <= m; i++)p[i] = i;
sort(p.begin() + 1, p.end(), [&](int a, int b) {
if (v[a] == v[b])return a < b;
else return v[a] > v[b];
});
for (int i = 1; i <= m; i++)
cout << p[i] << ' ' << v[p[i]] << endl;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/
L:Recover Statistics
大意:
思路:
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define vi vector<int>
#define vii vector<pair<int, int>>
#define ff first
#define ss second
// ++ ~! */+- <<>> <> == &^| &&|| =
void solve()
{
int a, b, c;cin >> a >> b >> c;
cout << 100 << endl;
for (int i = 1; i <= 50; i ++)
cout << a << ' ';
for (int i = 51; i <= 95; i ++)
cout << b << ' ';
for (int i = 96; i <= 99; i++)
cout << c << ' ';
cout << c + 1;
}
signed main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}
/* /\_/\
* (= ._.)
* / > \>
*/