2025CCPC邀请赛(南昌)VP(A,B,C,D,G,H,K,L)
有部分解法不给出思路
A.扭蛋
#include<bits/stdc++.h>
#define endl '\n'
#define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin)
#define fout freopen("C://Users//20321//Desktop//vscode_cpp//out.out", "w", stdout)
#define fl cout.flush()
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int N=2e5+5;
const ll mod=1e9+7;
ll t,n,m;
ll a[N];
// ll ksm(ll a, ll b) {
// ll res = 1;
// a %= mod;
// while (b > 0) {
// if (b & 1)
// res = res * a % mod;
// a = a * a % mod;
// b >>= 1;
// }
// return res%mod;
// }
ll k;
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
bool check(ll v){
ll sum=0;
ll id=0;
for(int i=1; i<=n; i++){
sum+=a[i];
if(sum>=v){
v-=i;
id=i;
break;
}
}
if(v/k>=n-id){
return true;
}
else return false;
}
void solve(){
cin >> n >> k;
ll tot=0;
for(int i=1; i<=n; i++){
cin >> a[i];
tot+=a[i];
}
sort(a+1,a+1+n,greater<ll>());
ll l=1,r=tot;
ll ans=r;
while(l<=r){
ll mid=(l+r)/2;
if(check(mid)){
ans=min(ans,mid);
r=mid-1;
}
else{
l=mid+1;
}
}
cout << ans << endl;
}
signed main()
{
//fread; //?cph??
fio();
cin >> t;
//t=1;
while(t--){
solve();
}
return 0;
}
B.精神胜利
#include<bits/stdc++.h>
#define endl '\n'
#define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin)
#define fout freopen("C://Users//20321//Desktop//vscode_cpp//out.out", "w", stdout)
#define fl cout.flush()
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int N=5005;
const ll mod=1e9+7;
// ll ksm(ll a, ll b) {
// ll res = 1;
// a %= mod;
// while (b > 0) {
// if (b & 1)
// res = res * a % mod;
// a = a * a % mod;
// b >>= 1;
// }
// return res%mod;
// }
const int inf=1000000;
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
int dis[505][505];
vector<int> ok[N];
void solve(){
int n,q;
cin>>n>>q;
if(n<=500){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j)dis[i][j]=inf;
else dis[i][j]=0;
}
}
for(int i=1;i<=n-1;i++){
string s;
cin>>s;
s="#"+s;
for(int j=1;j<=n-i;j++){
if(s[j]=='0'){
dis[i+j][i]=1;
}else{
dis[i][i+j]=1;
}
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++){
// cout<<dis[i][j]<<" ";
// }
// cout<<"\n";
// }
for(int i=1;i<=q;i++){
int a,b;
cin>>a>>b;
if(dis[a][b]==inf){
cout<<"-1\n";
}else{
cout<<dis[a][b]-1<<"\n";
}
}
}else{
for(int i=1;i<=n-1;i++){
string s;
cin>>s;
s="#"+s;
for(int j=1;j<=n-i;j++){
if(s[j]=='0'){
ok[i+j].push_back(i);
}else{
ok[i].push_back(i+j);
}
}
}
for(int i=1;i<=q;i++){
int a,b;
cin>>a>>b;
bool k=1;
for(auto to:ok[a]){
if(to==b){
k=0;
break;
}
}
cout<<k<<"\n";
}
}
}
signed main()
{
// fread; //?cph??
fio();
int t=1;
// cin >> t;
while(t--){
solve();
}
return 0;
}
C.虫洞
思路:如果我选择的一个[L,R]在x处出现了k次重叠,如果在y处(x<=y)出现了小于等于k次重叠,显然无论是x处线段延申到y或者y是由新的k个线段重叠而来,可以发现,我们仍然可以将线段分配成k组且组内互不相交,那么我们可以把题目理解成寻找标号在[L,R]的线段,使得他们在坐标轴排布后,单点重叠需要小于等于k次,由于这个具有单调性,双指针+区间最值线段树即可解决。
#include<bits/stdc++.h>
#define endl '\n'
#define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin)
#define fout freopen("C://Users//20321//Desktop//vscode_cpp//out.out", "w", stdout)
#define fl cout.flush()
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int N=2e5+5;
const ll mod=1e9+7;
const ll maxn=2e5+5;
struct tree {
ll v,la;
ll l, r;
}p[maxn << 2];
void build(ll i, ll l, ll r) {
p[i].l = l, p[i].r = r;
p[i].v = 0;
p[i].la=0;
if (l == r)return;
build(i << 1, l, l + r >> 1);
build(i << 1 | 1, (l + r >> 1) + 1, r);
}
void push_down(ll i){
if(p[i].la){
p[i<<1].v+=p[i].la;p[i<<1|1].v+=p[i].la;
p[i<<1].la+=p[i].la;p[i<<1|1].la+=p[i].la;
p[i].la=0;
}
}
void update(ll i, ll l,ll r, ll x) {//?
if (p[i].l==l&&p[i].r==r) {
p[i].v+=x;
p[i].la+=x;
return;
}
push_down(i);
ll mid = p[i].l + p[i].r >> 1;
if(l<= mid)update(i << 1,l, min(mid,r),x);
if(r>=mid+1)update(i << 1 | 1, max(l,mid+1),r,x);
p[i].v = max(p[i << 1].v, p[i << 1 | 1].v);
}
ll query(ll i, ll l, ll r) {
ll ans = 0;
if (p[i].l == l && p[i].r == r) {
return p[i].v;
}
push_down(i);
ll mid = p[i].l + p[i].r >> 1;
if (l <= mid)ans = max(ans, query(i << 1, l, min(mid, r)));
if (r >= mid + 1)ans = max(ans, query(i << 1 | 1, max(mid + 1, l), r));
return ans;
}
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
void solve(){
ll n,k;
cin>>n>>k;
vector<pair<ll,ll>>a(n+2);
for(ll i=1;i<=n;i++){
auto &[l,r]=a[i];
cin>>l>>r;
}
build(1,1,n);
deque<ll>que;
ll ans=0;
for(ll i=1;i<=n;i++){
auto [l,r]=a[i];
que.push_back(i),update(1,l,r,1);
while(query(1,1,n)>k){
auto [l1,r1]=a[que.front()];
update(1,l1,r1,-1);
que.pop_front();
}
ans=max(ans,(ll)que.size());
//ll u=query(1,1,n);
}
cout<<ans<<endl;
}
signed main()
{
fio();
// fread; //?cph??
ll t=1;
cin >> t;
//t=1;
while(t--){
solve();
}
return 0;
}
D.挑战图同构
思路:如果边值均为1,那么1-2-3和3-1-2是等价的。那么我们可以发现如果从小到大枚举边连接未连接的点,使得每次G1,G2的点构成的并查集具有相同的对应状态就是YES的条件。这里枚举连通分量然后再枚举边,开了两个并查集,对G1中的连通分量que1按上述枚举方式枚举,每次连同值边,直到值变了再连接G2.注意如果G1没修改,那么在que2中小于等于原值的边也不能产生影响。否则que2中小于原值的边也不能产生影响,然后等值边连接完后得构成和G1相同的并查集。为了保证que2能枚举完,推荐在que1中加个无穷大边,最后跳出即可。每次检测是Co2检测Co1连的边(Co2和Co1分别是G1,G2的并查集),然后Co1检测Co2连接的边,写得可能复杂了?
#pragma GCC optimize(3, "Ofast", "inline", "unroll-loops")
#include<iostream>
#include<queue>
#include<map>
#include<iomanip>
#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>
#include<functional>
#define endl '\n'
#define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin)
#define fout freopen("C://Users//20321//Desktop//vscode_cpp//out.out", "w", stdout)
#define fl cout.flush()
using namespace std;
typedef long long ll;
const ll INF = 1e18;
const int N = 2e5 + 5;
const ll mod = 1e9 + 7;
const ll maxn = 2e5 + 5;
void fio() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
struct s {
ll l, r, v;
friend bool operator<(const s& a, const s& b) {
return a.v < b.v;
};
};
ll find(ll x, vector<ll>& a) {
if (x == a[x])return x;
else return a[x] = find(a[x], a);
}
void solve() {
ll n, m, k;
cin >> n >> m >> k;
vector<vector<pair<ll, ll>>>g1(n+2), g2(n+2);
vector<ll>co1(n + 2, 0), co2(n + 2, 0);
for (ll i = 1; i <= n; i++)co1[i] = co2[i] = i;
vector<bool>vi1(n + 2, 0), vi2(n + 2, 0), vi(n + 2, 0);
for (ll i = 1; i <= m; i++) {
ll l, r, v;
cin >> l >> r >> v;
g1[l].push_back({ r,v });
g1[r].push_back({ l,v });
}
for (ll i = 1; i <= k; i++) {
ll l, r, v;
cin >> l >> r >> v;
g2[l].push_back({ r,v });
g2[r].push_back({ l,v });
}
auto dfs = [&](ll x, auto&& dfs, vector<vector<pair<ll, ll>>>& g, vector<ll>& b, vector<bool>& vis, vector<s>& f)->void {
vis[x] = 1;
vi[x] = 1;
b.push_back(x);
for (auto& [to, v] : g[x]) {
if (!vis[to])f.push_back({ to,x,v });
}
for (auto& [to, v] : g[x]) {
if (vis[to])continue;
dfs(to, dfs, g, b, vis, f);
}
};
auto ck = [&](ll x)->int {
vector<ll>ls1, ls2;
vector<s>ls;
vector<s>que1, que2;
dfs(x, dfs, g1, ls1, vi1, que1);
dfs(x, dfs, g2, ls2, vi2, que2);
sort(ls1.begin(), ls1.end());
sort(ls2.begin(), ls2.end());
if (ls1 != ls2)return 0;
sort(que1.begin(), que1.end());
sort(que2.begin(), que2.end());
if(que1.size()==0&&que2.size()==0)return 1;
else if(que1.size()==0||que2.size()==0)return 0;
ll l = 0;
ll cc = que1[0].v;
bool flag = 0;
que1.push_back({ 0,7,(ll)1e18 });
for (ll i = 0; i < que1.size(); i++) {
auto [x, y, v] = que1[i];
if (cc == v) {
ls.push_back(que1[i]);
ll fx = find(x, co1);
ll fy = find(y, co1);
if (fx == fy)continue;
co1[fx] = fy;
flag = 1;
}
else {
if (flag == 0) {
while (l < que2.size() && que2[l].v <= cc) {
auto [x1, y1, v1] = que2[l];
l++;
if (find(x1, co2) != find(y1, co2))return 0;
}
}
else {
if (l == que2.size())return 0;
while(l<que2.size()&&que2[l].v<cc){
auto [x1, y1, v1] = que2[l];
l++;
ll fx = find(x1, co2);
ll fy = find(y1, co2);
if(fx!=fy)return 0;
}
while (l < que2.size() && que2[l].v == cc) {
auto [x1, y1, v1] = que2[l];
l++;
ll fx = find(x1, co2);
ll fy = find(y1, co2);
if (find(x1, co1) != find(y1, co1))return 0;
if (fx == fy)continue;
co2[fx] = fy;
}
for (auto [x1, y1, z1] : ls) {
if (find(x1, co2) != find(y1, co2))return 0;
}
}
if (i == que1.size() - 1)break;
ls.clear();
flag = 0;
cc = v;
ls.push_back(que1[i]);
ll fx = find(x, co1);
ll fy = find(y, co1);
if (fx == fy)continue;
co1[fx] = fy;
flag = 1;
}
}
return 1;
};
for (ll i = 1; i <= n; i++) {
if (vi[i])continue;
if (!ck(i)) {
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
}
signed main()
{
fio();
// fread; //?cph??
ll t = 1;
cin >> t;
//t=1;
while (t--) {
solve();
}
return 0;
}
G.玻璃碎晶
#include<bits/stdc++.h>
#define endl '\n'
#define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin)
#define fout freopen("C://Users//20321//Desktop//vscode_cpp//out.out", "w", stdout)
#define fl cout.flush()
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int N=2e5+5;
const ll mod=1e9+7;
ll t,n,m;
// ll ksm(ll a, ll b) {
// ll res = 1;
// a %= mod;
// while (b > 0) {
// if (b & 1)
// res = res * a % mod;
// a = a * a % mod;
// b >>= 1;
// }
// return res%mod;
// }
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
void solve(){
cin >> n;
if(n==1 || n==2 || n==4){
cout << -1 << endl;
return;
}
if(n%3==0 || n%3==2){
cout << n/3 << endl;
}
else{
cout << n/3-1 << endl;
}
}
signed main()
{
//fread; //?cph??
fio();
cin >> t;
//t=1;
while(t--){
solve();
}
return 0;
}
H.珍珠链
思路:可想-1的条件是出现\(a_i<i\)。那么我们只需去卡这个边界即可,第i位最多可以等\(a_i-i\)轮,那么我们从后往前维护最小\(a_i-i\),然后边走边卡边界即可
#include<bits/stdc++.h>
#define endl '\n'
#define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin)
#define fout freopen("C://Users//20321//Desktop//vscode_cpp//out.out", "w", stdout)
#define fl cout.flush()
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int N=2e5+5;
const ll mod=1e9+7;
//ll t,n,m;
// ll ksm(ll a, ll b) {
// ll res = 1;
// a %= mod;
// while (b > 0) {
// if (b & 1)
// res = res * a % mod;
// a = a * a % mod;
// b >>= 1;
// }
// return res%mod;
// }
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
void solve(){
ll n;
cin>>n;
vector<ll>a(n+2);
bool flag=0;
for(ll i=1;i<=n;i++){
cin>>a[i];
if(a[i]<i)flag=1;
}
if(flag){
cout<<-1<<endl;
return ;
}
vector<ll>pre(n+2,1e18);
for(ll i=n;i>=1;i--){
pre[i]=min(pre[i+1],a[i]-i);
}
ll op=1;
ll ans=0;
ll now=0;
ll wait=0;
for(ll i=1;i<=n;i++){
ll kk=pre[i]-wait;
ll u=min(now,kk);
wait+=u;
now-=u;
ans+=u;
op+=u;
now+=a[i]-op;
op++;
ans++;
// cout<<now<<" "<<ans<<endl;
}
ans+=now;
cout<<ans<<endl;
}
signed main()
{
fio();
// fread; //?cph??
ll t=1;
cin >> t;
//t=1;
while(t--){
solve();
}
return 0;
}
k.不许偷吃
思路:注意总和为4的倍数且现在说的数是模4得出的数。0随便放,3和1匹配,如果3多,那就3 2 2 匹配(一定出现偶数个3),如果1多,那就2 1 1匹配(一定出现偶数次1),然后剩下就直接放剩下的2即可。
这里为了方便,在上述构造方式构造完了后,把可能剩下的数加到数组里了,最后线性检测正确性即可
#include<bits/stdc++.h>
#define endl '\n'
#define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin)
#define fout freopen("C://Users//20321//Desktop//vscode_cpp//out.out", "w", stdout)
#define fl cout.flush()
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int N=2e5+5;
const ll mod=1e9+7;
//ll t,n,m;
// ll ksm(ll a, ll b) {
// ll res = 1;
// a %= mod;
// while (b > 0) {
// if (b & 1)
// res = res * a % mod;
// a = a * a % mod;
// b >>= 1;
// }
// return res%mod;
// }
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
void solve(){
ll n;
cin>>n;
vector<ll>a(n+2);
vector<vector<ll>>sz(5);
for(ll i=1;i<=n;i++){
cin>>a[i];
ll u=a[i]%4;
sz[u].push_back(i);
}
vector<ll>ans;
for(auto j:sz[0])ans.push_back(j);
ll l3=0,l1=0,l2=0;
while(l3<sz[3].size()&&l1<sz[1].size()){//3 1
ans.push_back(sz[3][l3]);
ans.push_back(sz[1][l1]);
l3++;
l1++;
}
while(l3+1<sz[3].size()&&l2<sz[2].size()){// 3 3 2
ans.push_back(sz[3][l3]);
l3++;
ans.push_back(sz[3][l3]);
l3++;
ans.push_back(sz[2][l2]);
l2++;
}
while(l1+1<sz[1].size()&&l2<sz[2].size()){// 2 1 1
ans.push_back(sz[2][l2]);
l2++;
ans.push_back(sz[1][l1]);
l1++;
ans.push_back(sz[1][l1]);
l1++;
}
while(l2<sz[2].size()){
ans.push_back(sz[2][l2]);
l2++;
}
while(l1<sz[1].size()){
ans.push_back(sz[1][l1]);
l1++;
}
while(l3<sz[3].size()){
ans.push_back(sz[3][l3]);
l3++;
}
ll flag=0;
ll sum=0;
for(auto j:ans){
sum+=a[j];
sum%=4;
if(sum==1)flag=1;
}
if(flag)cout<<-1<<endl;
else {
for(auto j:ans)cout<<j<<" ";
cout<<endl;
}
}
signed main()
{
fio();
// fread; //?cph??
ll t=1;
cin >> t;
//t=1;
while(t--){
solve();
}
return 0;
}
L.羽球比赛
#include<bits/stdc++.h>
#define endl '\n'
#define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin)
#define fout freopen("C://Users//20321//Desktop//vscode_cpp//out.out", "w", stdout)
#define fl cout.flush()
using namespace std;
typedef long long ll;
const ll INF=1e18;
const int N=2e5+5;
const ll mod=1e9+7;
ll t,n,m;
// ll ksm(ll a, ll b) {
// ll res = 1;
// a %= mod;
// while (b > 0) {
// if (b & 1)
// res = res * a % mod;
// a = a * a % mod;
// b >>= 1;
// }
// return res%mod;
// }
void fio(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
}
void solve(){
ll a,b;
cin >> a >> b;
if((a>=21 && a-b>=2) || (a==30)){
cout << "Alice" << endl;
return;
}
if((b>=21 && b-a>=2) || (b==30)){
cout << "Bob" << endl;
return;
}
cout << "Underway" << endl;
return;
}
signed main()
{
//fread; //?cph??
fio();
//cin >> t;
t=1;
while(t--){
solve();
}
return 0;
}

浙公网安备 33010602011771号