22级ACM 4.16 周赛 题解

文章提供了多道编程竞赛题目(A至I题)的解题思路和代码示例,涉及线段树、离散化、拓扑排序等算法,同时作者分享了对参赛者表现和题解质量的观察。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这场能题解写的感觉没多少其实(真的不是因为懒),既然有人想要题解,那么就随便写一下吧,其实大部分的题都有人写出来,感觉这场真的不需要

A 题 题解

Count Interval AtCoder - abc233_d_霾まる的博客-优快云博客

B题 题解

2021四川省icpc省赛H题 Nihongo wa Muzukashii Desu 日本語は難しいです!_霾まる的博客-优快云博客

C题 题解:

线段树的典题,输入 去重 二分 线段树区间修改 最后求值即可。emmmmm,可能难在了 离散化去重的思想?还是线段树的板子? (本来想拉道线段树的板子,看看大家学的怎么样,拉的这道题没有达到效果,感觉这道题拉的挺失败的,应该拉道更板子的

(随机挑选一个代码看着比较顺眼的代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<set>
#include<algorithm>
#include<map>
#include<string.h>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
int t;
int n,an;
int ans=0;
struct we{
	int l,r;
}hh[100005];
int tr[400005];
bool v[10000000];
int b[400005];
void add(int l,int r,int x,int L,int R,int id){
	if(L<=l&&R>=r){
		tr[x]=id;
		return;
	}
	if(tr[x]){
		tr[x<<1]=tr[x];
		tr[x<<1|1]=tr[x];
		tr[x]=0;
	}
	int mid=(l+r)>>1;
	if(L<=mid)add(l,mid,x<<1,L,R,id);
	if(R>mid)add(mid+1,r,x<<1|1,L,R,id);
}



void cha(int x,int l,int r){
	if(l==r){
		if(v[tr[x]]==0&&tr[x]){
			ans++;
			v[tr[x]]=1;
		}
		return;
	}
	if(tr[x]){
		tr[x<<1]=tr[x<<1|1]=tr[x];
		tr[x]=0;
	}
	int mid=(l+r)>>1;
	cha(x<<1,l,mid);
	cha(x<<1|1,mid+1,r);
}



int main(){
	ios::sync_with_stdio(false);
	cin.tie();
	cout.tie();
	cin>>t;
	while(t--){
		cin>>n;
		memset(v,0,sizeof v);
		memset(tr,0,sizeof tr);
		an=0;
		ans=0;
		for(int i=1;i<=n;i++){
			cin>>hh[i].l>>hh[i].r;
			b[++an]=hh[i].l;
			b[++an]=hh[i].r;
		}
		sort(b+1,b+an+1);
		an=unique(b+1,b+an+1)-b-1;
		for(int i=1;i<=n;i++){
			int l=lower_bound(b+1,b+an,hh[i].l)-b;
			int r=lower_bound(b+1,b+an,hh[i].r)-b;
			add(1,an,1,l,r,i);
		}
		cha(1,1,an);
		
		printf("%d\n",ans);
	}
	
}

D题 

The 2021 CCPC Guangzhou Onsited

是这场中的 H  签到题

题解的话,看这篇比较好,我觉得写的优雅 又 美丽

2021CCPC广州 H. Three Integers_h three integers__sky123_的博客-优快云博客

E 题

这题比D题还要简单,不过不知道为什么没有人写。

推结论的话,也很好推。不推结论的话,打表 或者 手模样例,最多到5,就能发现规律。可惜没有人写。(唉,这道题网上的题解感觉写的都挺烂,什么题解,还要我亲自动手写)

我们很容易推得

​​​​​​​

 

#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<map>
#include <unordered_map>
#include<set>
#include<tuple>
#include<numeric>
#include<stack>
using namespace::std;
typedef long long  ll;
inline char nc() {
    static char buf[1000000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
template <typename _Tp> inline void read(_Tp&sum) {
    char ch = nc(); sum = 0;
    while (!(ch >= '0'&&ch <= '9')) ch = nc();
    while (ch >= '0'&&ch <= '9') sum = (sum << 3) + (sum << 1) + (ch - 48), ch = nc();
}
inline __int128 read128(){
    __int128 x = 0, f = 1;
    char ch128 = getchar();
    while(ch128 < '0' || ch128 > '9'){
        if(ch128 == '-')
            f = -1;
        ch128 = getchar();
    }
    while(ch128 >= '0' && ch128 <= '9'){
        x = x * 10 + ch128 - '0';
        ch128 = getchar();
    }
    return x * f;
}
inline void print128(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print128(x / 10);
    putchar(x % 10 + '0');
}
//struct dian{
//    double x,y;
//}A,B,C,D,E,F;//点
//cin>>A.x>>A.y>>B.x>>B.y>>C.x>>C.y>>D.x>>D.y>>E.x>>E.y>>F.x>>F.y;
//double len(dian x,dian y){
//    return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
//}//两点之间距离
//double xj(dian x,dian y,dian z){
//    x.x-=y.x;
//    x.y-=y.y;
//    z.x-=y.x;
//    z.y-=y.y;
//    return x.x*z.y-x.y*z.x;
//}//叉积
int n,t;
const ll N=998244353;
ll ksm(ll x,ll y){
    ll oper=1;
    while (y) {
        if (y&1) {
            oper=oper*x%N;
        }
        x=x*x%N;
        y>>=1;
    }
    return oper;
}
void wanyurukong(){
    cin>>n;
    ll na=1;
    if (n<=3) {
        for (int i =1; i<=n; i++) {
            na*=i;
        }
        
    }
    else{
        na=3*ksm(2, n-2)%N;
        
    }
    cout<<na<<"\n";
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(); cout.tie();
    cin>>t;
    while (t--) {
        wanyurukong();
    }
    //wanyurukong
    return 0;
}
 

 F题

输出肯定是不行的。

我们直接手动模拟除法就好,除不了,就是乘10,然后小数点后推一位。然后细心一点就好了(直接放你们其中一个人AC代码了

#include<iostream>
using namespace std;
int c[1005];
int main()
{
	int a,b,k;
	cin>>a>>b>>k;
	if(a==b)
	{
		cout<<1<<".";
		for(int i=1;i<=k;i++)cout<<0;
	}
	else
	{
		int z=0;
		while(z<=k+1)
		{
			z++;
			a*=10;
			c[z]=a/b;
			if(a>=b&&a!=0)a=a%b;
		}
		if(c[k+1]>=5)c[k]+=1;
		cout<<0<<".";
		for(int i=1;i<=k;i++)cout<<c[i];
	}
	return 0;
}

G 题

去年的ccpc河南省省赛的题,过了签到,过了这道题,再过一道树上MEX,罚时少一点,就可以金牌了。

题解:2022河南省CCPC省赛H题旋转水管_霾まる的博客-优快云博客

H 题

吉林省赛 拓扑排序的板子题,应该是没人会的,可以都去学一下,这个类似于一种思想。

这道题的话,感觉没什么好说的。就是要确定的,所以我们从可以唯一确定的开始推,然后不断修改行列的状态,再找下一个唯一确定的,典型拓扑排序。

/*Looking! The blitz loop this planet to search way
 
 Only my RAILGUN can shoot it 今すぐ
 
 身体中を  光の速さで
 
 駆け巡った確かな予感
 
 掴め! 望むものなら残さず
 
 輝ける自分らしさで
 
 信じてるよ  あの日の誓いを
 
 この瞳に光る涙それさえも  強さになるから
 
 */
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include <unordered_map>
#include<set>
#include<tuple>
#include<numeric>
using namespace::std;
typedef long long  ll;
inline char nc() {
    static char buf[1000000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
template <typename _Tp> inline void read(_Tp&sum) {
    char ch = nc(); sum = 0;
    while (!(ch >= '0'&&ch <= '9')) ch = nc();
    while (ch >= '0'&&ch <= '9') sum = (sum << 3) + (sum << 1) + (ch - 48), ch = nc();
}
inline __int128 read128(){
    __int128 x = 0, f = 1;
    char ch128 = getchar();
    while(ch128 < '0' || ch128 > '9'){
        if(ch128 == '-')
            f = -1;
        ch128 = getchar();
    }
    while(ch128 >= '0' && ch128 <= '9'){
        x = x * 10 + ch128 - '0';
        ch128 = getchar();
    }
    return x * f;
}
inline void print128(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print128(x / 10);
    putchar(x % 10 + '0');
}
//struct dian{
//    double x,y;
//}A,B,C,D,E,F;//点
//cin>>A.x>>A.y>>B.x>>B.y>>C.x>>C.y>>D.x>>D.y>>E.x>>E.y>>F.x>>F.y;
//double len(dian x,dian y){
//    return sqrt((x.x-y.x)*(x.x-y.x)+(x.y-y.y)*(x.y-y.y));
//}//两点之间距离
//double xj(dian x,dian y,dian z){
//    x.x-=y.x;
//    x.y-=y.y;
//    z.x-=y.x;
//    z.y-=y.y;
//    return x.x*z.y-x.y*z.x;
//}//叉积
int n;
int ff[1005][1005];
int h[1005],l[1005];
int s1[1005],s2[1005];
int enddh[1005],enddl[1005];
pair<int, int>jkl;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(); cout.tie();
    cin>>n;
    for (int i =1; i<=n; i++) {
        for (int j =1; j<=n; j++) {
            cin>>ff[i][j];
            if (ff[i][j]!=-1) {
                h[i]++;
                l[j]++;
                s1[i]^=ff[i][j];
                s2[j]^=ff[i][j];
            }
        }
    }
    for (int i =1; i<=n; i++) {
        cin>>enddh[i];
    }
    for (int i =1; i<=n; i++) {
        cin>>enddl[i];
    }
    queue<pair<int, int>>q;
    for (int i =1; i<=n; i++) {
        for (int j =1; j<=n; j++) {
            if (ff[i][j]==-1&&(h[i]==n-1||l[j]==n-1)) {
                q.push({i,j});
            }
        }
    }
    while (!q.empty()) {
        jkl=q.front();q.pop();
        if (h[jkl.first]==n-1) {
            ff[jkl.first][jkl.second]=enddh[jkl.first]^s1[jkl.first];
        }
        if(l[jkl.second]==n-1){
            ff[jkl.first][jkl.second]=enddl[jkl.second]^s2[jkl.second];
        }
        s2[jkl.second]^=ff[jkl.first][jkl.second];
        s1[jkl.first]^=ff[jkl.first][jkl.second];
        h[jkl.first]++;
        l[jkl.second]++;
        if ( l[jkl.second]==n-1) {
            for (int i =1; i<=n; i++) {
                if (ff[i][jkl.second]==-1) {
                    q.push({i,jkl.second});
                    break;
                }
            }
        }
        if (h[jkl.first]==n-1) {
            for (int i =1; i<=n; i++) {
                if (ff[jkl.first][i]==-1) {
                    q.push({jkl.first,i});
                    break;
                }
            }
        }
    }
    for (int i =1; i<=n; i++) {
        for (int j =1; j<=n; j++) {
            if (ff[i][j]==-1) {
                printf("-1\n");return 0;
            }
        }
    }
    for (int i =1; i<=n; i++) {
        for (int j =1; j<=n; j++) {
            printf("%d ",ff[i][j]);
        }
        printf("\n");
    }
    return 0;
}

I 题

没什么好说的,就是树状数组的板子题。找一下 逆序对 就好,这道题甚至不需要离散化。

树状数组专题的第一道题 是需要 离散化的 找逆序对,按道理来说应该能直接写出来的。

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<set>
#include<algorithm>
#include<map>
#include<string.h>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
int t,x,y,n;
ll a[500005];
ll b[500005];
ll lowbit(ll x){
	return x&(-x);	
}
void add(ll x){
	for(int i=x;i<=n;i+=lowbit(i)){
		b[i]++;
	}
}
ll cha(ll x){
	ll ans=0;
	for(int i=x;i>0;i-=lowbit(i)){
		ans+=b[i];
	}
	return ans;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie();
	cout.tie();
	cin>>t;
	while(t--){
		memset(b,0,sizeof b);
		cin>>n;
		for(int i=1;i<=n;i++)cin>>a[i];
		ll ans=0;
		for(int i=n;i>=1;i--){
//			cout<<cha(a[i])<<"***\n";
			ans+=cha(a[i]);
			add(a[i]);
		}
		printf("%lld\n",ans);
	}
	
}

本来预期 人均 5~6题,中间还感觉题拉简单了,后来发现 感觉 早了。

记得好好打专题+补题。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值