Dashboard - 2024 CCPC Liaoning Provincial Contest - Codeforces
过题难度
B A J C L E G
铜奖 4 953
银奖 6 991
金奖 8 1664
B:
模拟题
// Code Start Here
string s;
cin >> s;
reverse(all(s));
cout << s << endl;
A:很明显的哈希一下,然后去重即可,这里set和map都可以
// Code Start Here
string s;
getline(cin , s);
for(int i = 0;i<sz(s);i++){
if((s[i] >= 'A' && s[i] <= 'Z')){
s[i] += 32;
}
}
set<string> st;
for(int i = 0;i<sz(s);i++){
if((s[i] >= 'a' && s[i] <= 'z') || (s[i] >= 'A' && s[i] <= 'Z')){
int j = i;
string t = "";
while((s[j] >= 'a' && s[j] <= 'z') || (s[j] >= 'A' && s[j] <= 'Z')) t += s[j++];
i = j;
st.insert(t);
}
}
int q;
cin >> q;
while(q--){
string t;
cin >> t;
if(st.find(t) != st.end())st.erase(t);
}
// for(auto i : st)cout << i <<" ";
cout << sz(st) << endl;
J
模拟前后两次的人数
// Code Start Here
int n;
cin >> n;
int a , b , c;
cin >> a >> b >> c;
vector<int> x(n + 1) , y (n + 1);
for(int i = 1;i<=n;i++)cin >> x[i] >> y[i];
int d;
cin >> d;
int before = 0 , after = 0;
for(int i = 1;i<=n;i++){
if(x[i] + y[i] >= c){
before++;
}
}
for(int i = 1;i<=n;i++) x[i] = min(a , x[i] + d);
for(int i = 1;i<=n;i++){
if(x[i] + y[i] >= c){
after++;
}
}
cout <<after - before << endl;
C
DFS跑一遍每个插座和插排的功率,然后贪心跑一遍判断即可
// Code Start Here
int n;
cin >> n;
vector<int> w(n + 1);
vector<vector<int>> g(n + 1);
vector<int> f(n + 1);
for(int i = 1;i<=n;i++){
int u;
cin >> u >> w[i];
g[u].push_back(i);
}
w[0] = 2200;
auto dfs = [&](auto &&self , int u)->void{
if(g[u].empty())f[u] += w[u];
for(auto v : g[u]){
self(self,v);
f[u] += f[v];
}
};
dfs(dfs , 0);
vector<int> e , ee;
for(int i = 0;i<=n;i++){
if(!g[i].empty()){
e.push_back(f[i]);
ee.push_back(w[i]);
}
}
sort(all(e)) , sort(all(ee));
bool flag = true;
for(int i = 0;i<sz(e);i++){
if(e[i] > ee[i] || e[i] > w[0])flag = false;
}
cout << ( flag ? "YES" : "NO") <<endl;
L
题意:
2024年起,每平年 +1 层数。但有特殊规则,年份必须是 4 的倍数,且不能是 100 的倍数但不是 10000 的倍数,否则是平年。到第 k 层的时候,是哪一年
思路:
可以不断贪心,更简单的方法是二分年份,然后找第k个合法年份。
计算到年份 x 之间,有多少个平年。遍历 i = 4, 400, 40000, ... 逐个计算:x / i 表示小于等于 x 有多少个 i 的倍数(4, 400, 40000, ...)x / (25 * i) 表示去掉那些是100倍数但不是10000倍数的年数。x - sum 表示有效的龙之研习年份数量,看看是不是到达了第 n + 1533 个。这里的 1533 是因为:2024是第0层,到2024年底总共经历了 2024 - 1533 = 491 个有效年份(实际上这1533是题目设定的初始偏移值,具体是为了校正年份起点和层数的关系)
// Code Start Here
int t;
cin >> t;
while(t--){
int n;
cin >> n;
int l = 2025 , r = 2e18;
auto check = [&](int x)->bool{
int sum = 0;
for(int i = 4;i<=x;i*= 100){
sum += x / i - x / (25 * i);
}
return (x - sum) >= (n + 1533);
};
while(l <= r){
int mid = l + r >> 1;
if(check(mid)) r = mid - 1;
else l = mid + 1;
}
cout << l << endl;
}
E
一道大模拟
// Code Start Here
int t;
cin >> t;
auto solve = [&]()->void{
int x, y;
cin >> x >> y;
if(x*y %4 !=0){
cout << "NO\n";
return ;
}
vector a(x+1, vector<int>(y+1, 0));
auto yes = [&](){
cout << "YES\n";
for(int i=1; i<=x; ++i){
for(int j=1; j<=y; ++j) cout << a[i][j] << " ";
cout << endl;
}
};
if(x % 4 == 0){
int cnt = 1;
for(int j=1; j<=y; j++){
for(int i=1; i<=x; i+=4){
a[i][j] = a[i+1][j] = a[i+2][j] = a[i+3][j] = cnt++;
}
}
yes();
return;
}
if(y % 4 ==0){
int cnt=1;
for(int i=1; i<=x; i++){
for(int j=1; j<=y; j+=4){
a[i][j] = a[i][j+1] = a[i][j+2] = a[i][j+3] = cnt++;
}
}
yes();
return;
}
if(x%2 ==0 && y%2 ==0){
if(y >=6 && (y-6)%4 ==0){
for(int i=1; i<=x; i+=2){
int temp = (i/2)*((y-6)/4*2 +3) +1;
a[i][1] = a[i][2] = a[i][3] = a[i+1][1] = temp;
a[i][4] = a[i][5] = a[i][6] = a[i+1][6] = temp+1;
a[i+1][2] = a[i+1][3] = a[i+1][4] = a[i+1][5] = temp+2;
int cnt = temp+3;
for(int j=7; j<=y; j+=4){
a[i][j] = a[i][j+1] = a[i][j+2] = a[i][j+3] = cnt++;
a[i+1][j] = a[i+1][j+1] = a[i+1][j+2] = a[i+1][j+3] = cnt++;
}
}
yes();
return;
}
else if(x >=6 && (x-6)%4 ==0){
for(int j=1; j<=y; j+=2){
int temp = (j/2)*((x-6)/4*2 +3) +1;
a[1][j] = a[2][j] = a[3][j] = a[1][j+1] = temp;
a[4][j] = a[5][j] = a[6][j] = a[6][j+1] = temp+1;
a[2][j+1] = a[3][j+1] = a[4][j+1] = a[5][j+1] = temp+2;
int cnt = temp+3;
for(int i=7; i<=x; i+=4){
a[i][j] = a[i+1][j] = a[i+2][j] = a[i+3][j] = cnt++;
a[i][j+1] = a[i+1][j+1] = a[i+2][j+1] = a[i+3][j+1] = cnt++;
}
}
yes();
return;
}
}
cout << "NO\n";
};
while(t--){
solve();
}
G
题意:给定一个长度为n的数组,求存在多少个子数组满足最大 值出现至少k 次。
思路:对于每一个位置i,我们可以考虑其作为第一个最大值时对答案的贡献,即能保证不重不漏的计数。不妨设:Li 为以 i 为起点,从右往左第一个比ai 大的元素的位置;Ri 为以 i 为起点,从左往右第一个比ai 大的元素的位置;lsti 为相对于当前位置 i,ai 上一次出现的位置;nxti 为相对于当前位置 i,ai 第 k 次出现的位置。
其中,Li 和Ri 可以通过单调栈计算,lsti 和nxti 则可以通过对值域开桶,根据每个位置在对应的桶中的相对位置进行计算。对于当前位置i 作为第一个最大值的数组:其左端点的合法范围是(max(lsti,Li),i],其右端点的合法范围是[i,min(nxti,Ri))。最后,统计每个位置作为第一个最大值时的贡献,即能求出结果
// Code Start Here
int t;
cin >> t;
while(t--){
int n , k;
cin >> n >> k;
vector<int> a(n + 1) , l (n + 1) , r(n + 1);
vector<vector<int>> num(n + 1);
for(int i = 1;i<=n;i++){
cin >> a[i];
num[a[i]].push_back(i);
}
int ans = 0;
vector<int> left , right;
for(int i = 1;i<=n;i++){
while(!left.empty() && a[left.back()] <=a[i])left.pop_back();
if(left.empty())l[i] = 1;
else l[i] = left.back() + 1;
left.push_back(i);
}
for(int i = n;i>=1;i--){
while(!right.empty() && a[right.back()] <= a[i])right.pop_back();
if(right.empty())r[i] = n;
else r[i] = right.back() - 1;
right.push_back(i);
}
for(int i = n;i>=1;i--){
if(sz(num[i]) >= k){
for(int j = 0;j + k - 1 < sz(num[i]);j++){
int p = num[i][j] , q = num[i][j + k - 1];
int l_ = l[p] , r_ = r[p];
if(j >= 1) l_ = max(l_ , num[i][j - 1] + 1);
if(r_ >= q)ans += (p - l_ + 1) *(r_ - q + 1);
}
}
}
cout << ans << endl;
}