zoukankan      html  css  js  c++  java
  • Codeforces 1305 (div1+div2) 题解 (ABCDEFG)

    比赛链接:https://codeforces.com/contest/1305

    div1,2合场。我感觉这次比赛总体不难,考察思维为主

    思维卡住了(比如说我)就很惨了

    A. Kuroni and the Gifts

    签到,略

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    typedef long long ll;
    ll read(){ll x; if(scanf("%lld",&x)==-1)exit(0); return x;}
    const int N=100010;
    int a[N],b[N];
    signed main(){
    	ios_base::sync_with_stdio(0); cin.tie(0);
    	int t=read();
    	while(t--){
    		int n=read();
    		repeat(i,0,n)a[i]=read();
    		repeat(i,0,n)b[i]=read();
    		sort(a,a+n); sort(b,b+n);
    		repeat(i,0,n)printf("%d ",a[i]); puts("");
    		repeat(i,0,n)printf("%d ",b[i]); puts("");
    	}
    	return 0;
    }
    

    B. Kuroni and Simple Strings

    这题据我所知有三种做法,对应三种复杂度

    题目突破口就是找到临界位置,这个位置左边的'('全部删除,')'全部保留,位置右边正好反一下

    第一种像我一样枚举临界位置,\(O(n^2)\)

    第二种也是算临界位置,但是用二分优化,\(O(n\log n)\)

    第三种用左右指针逼近,相遇点即临界位置,\(O(n)\)

    第一种最好写所以想都没想就开莽了

    大力出奇迹

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    string s;
    int count(int l,int r,char c){ //在区间[l,r]内有多少个字符c
    	int ans=0;
    	repeat(i,l,r+1)
    		ans+=s[i]==c;
    	return ans;
    }
    void print(int l,int r,char c){ //输出区间[l,r]内所有字符c的位置
    	repeat(i,l,r+1)
    	if(s[i]==c)
    		cout<<i+1<<' ';
    }
    int len;
    int solve(){ //找到临界位置
    	cin>>s;
    	len=s.length();
    	repeat(i,-1,len){
    		if(count(0,i,'(')==count(i+1,len-1,')'))
    			return i;
    	}
    	return -1; //程序根本不会运行到这里所以请忽略,只是为了防止烦人的编译器警告
    }
    signed main(){
    	ios_base::sync_with_stdio(0); cin.tie(0);
    	int p=solve(),cnt=count(0,p,'(');
    	if(cnt==0)cout<<0<<endl;
    	else{
    		cout<<1<<endl;
    		cout<<cnt*2<<endl;
    		print(0,p,'(');
    		print(p+1,len-1,')');
    	}
    	return 0;
    }
    

    C. Kuroni and Impossible Calculation

    学长:你看这个m的范围就没有一点想法吗

    想法就是开1000个桶把数据放进去,然后暴力 \(O(m^2)\) 解决问题

    大力出奇迹)*2

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    typedef long long ll;
    const int N=200010;
    int a[N],h[N],cnt[N];
    int n,m;
    signed main(){
    	ios_base::sync_with_stdio(0); cin.tie(0);
    	cin>>n>>m;
    	repeat(i,0,n)cin>>a[i],cnt[a[i]%m]++,h[a[i]%m]=a[i];
    	repeat(i,0,m)if(cnt[i]>1)cout<<0<<endl,exit(0);
    	ll ans=1%m;
    	repeat(i,0,m)
    	if(cnt[i])
    	repeat(j,i+1,m)
    	if(cnt[j]){
    		if(h[i]>h[j])
    			ans=ans*(i-j)%m;
    		else
    			ans=ans*(j-i)%m;
    	}
    	cout<<(ans+m)%m<<endl;
    	return 0;
    }
    

    D. Kuroni and the Celebration

    这是一道交互题,熟悉交互题的写法对打cf还是很有帮助的

    因为要在 \(\lfloor \dfrac n 2 \rfloor\) 次询问内解决问题,所以每次询问都排除至少两个点就可以完成任务

    因此假如 \(x\)\(y\) 之间有边,\(y\)\(z\) 之间有边,那么询问 \(x,z\) 一定可以至少排除两个点(我们可以砍掉这两条边,询问范围缩小到 \(lca(x,z)\) 所在的子图中)

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    typedef long long ll;
    const int N=1010;
    int n; set<int> a[N]; //用set存不常见,注意风险
    int x,ans;
    void q(){
    	if(a[x].empty()){ //如果x没边了
    		cout<<"! "<<x<<endl;
    		exit(0);
    	}
    	int y=*a[x].begin();
    	if(a[x].size()==1 && a[y].size()==1){ //如果x只连y,y只连x
    		cout<<"? "<<x<<' '<<y<<endl;
    		cout.flush();
    		cin>>ans;
    		cout<<"! "<<ans<<endl;
    		exit(0);
    	}
    	if(a[y].size()==1){ //如果y只有一条边(找不到z)就把y当成x,重新来一次
    		x=y;
    		return;
    	}
    	int z=*a[y].begin();
    	if(z==x)z=*(++a[y].begin());
    	cout<<"? "<<x<<' '<<z<<endl;
    	cout.flush();
    	cin>>ans;
        //砍边时刻
    	a[x].erase(y);
    	a[y].erase(x);
    	a[y].erase(z);
    	a[z].erase(y);
    	x=ans;
    }
    signed main(){
    	ios_base::sync_with_stdio(0); cin.tie(0);
    	cin>>n;
    	repeat(i,0,n-1){
    		int x,y; cin>>x>>y;
    		a[x].insert(y);
    		a[y].insert(x);
    	}
    	x=1;
    	while(1)q();
    	return 0;
    }
    

    E. Kuroni and the Score Distribution

    令人智熄的构造题)

    首先构造出平衡数最大的序列:\(1,2,...,n\)

    然后我们试着往后移动 \(n\) 发现 \(n\) 每加 \(2\) ,平衡数会减 \(1\)

    我一直以为n+1,平衡数+1,一直到比赛结束,呜呜

    当然如果 \(n\) 移到很远的地方平衡数就不会变了

    这时我们就要移动 \(n-1\)

    为了避免冲突,我们将“很远”的位置从 \(9e8\) 开始每 \(1e4\) 放置一个数

    比如我要放 \(3\) 个数到很远的位置就放在 \(800000000,800010000,800020000\)

    (为什么要 \(1e4\) 这么多呢,因为我可以保证前面任意一个数都小于 \(1e4\)

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    typedef long long ll; 
    const int N=1010;
    int n,m;
    signed main(){
    	ios_base::sync_with_stdio(0); cin.tie(0);
    	cin>>n>>m;
    	repeat(i,1,n+1){
    		int l=i%2,r=i-2;
    		int s=(l+r)*(r-l+2)/4;
    		if(s>=m){
    			repeat(j,1,i)cout<<j<<' ';
    			cout<<i+(s-m)*2<<' ';
    			int k=9e8;
    			repeat(j,0,n-i)
    				cout<<k<<' ',k+=10000;
    			exit(0);
    		}
    	}
    	cout<<-1<<endl;
    	return 0;
    }
    

    F. Kuroni and the Punishment

    随机化?!

    随机化可以说是相当玄学,玄学中的玄学精彩的算法了

    我们先对 \(a_i\) 洗牌,洗完后取前 \(30\) 个数 \(^1\),再取与这些数 \(^1\) 绝对值相差 \(1\) 以内的所有数 \(^2\),再取这些数 \(^2\) 的所有质因数 \(^3\),再把这些数 \(^3\)当成公因数for一遍来更新答案

    可以发现,如果公因数是 \(2\) 或者 \(3\),取 \(1\) 个数也无所畏惧;如果是 \(4\) ,那么要让我取不到公因数的办法只能让尽量多的数模 \(4\)\(2\) 而且答案一定要小于 \(n\),这意味着至少一半的数模 \(4\) 不余 \(2\),算法也就只有大约 \(2^{-30}\) 的错误概率,真是巧妙

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    typedef long long ll; const int inf=~0u>>2;
    mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count());
    const int N=200010;
    #define int ll
    set<int> s;
    int n,a[N];
    void fac(int n){
    	for(int i=2;i*i<=n;i++)
    	if(n%i==0){
    		s.insert(i);
    		while(n%i==0)n/=i;
    	}
    	if(n>1)s.insert(n);
    }
    signed main(){
    	ios_base::sync_with_stdio(0); cin.tie(0);
    	cin>>n;
    	repeat(i,0,n)cin>>a[i];
    	repeat_back(i,3,n)swap(a[i],a[rnd()%i]);
    	repeat(i,0,min(30ll,n)){
    		fac(a[i]);
    		fac(a[i]+1);
    		fac(a[i]-1);
    	}
    	int ans=inf;
    	for(auto d:s){
    		int now=0;
    		repeat(i,0,n){
    			if(a[i]<d)now+=d-a[i];
    			else now+=min(a[i]%d,d-a[i]%d);
    		}
    		ans=min(ans,now);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    

    G. Kuroni and Antihype

    人生第一次补G题

    事实上看光代码也能理解思路,

    我们先加一个成员0

    显然成员关系会是一个图,如果发生邀请,我们将这条边涂上红色

    定义边权等于端点点权之和

    由于不能重复邀请,红色边构成了一棵树,且恰好 所有边权之和 减去 所有点权之和 就是这个方案的临时答案(这个结论谁想得到啊

    所以最终只要跑个最大生成树,用 \(s\) 从大到小遍历边权,然后遍历 \(s\) 的二进制子集,DSU维护连通

    #include <bits/stdc++.h>
    using namespace std;
    #define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
    #define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
    typedef long long ll;
    const int N=1<<18;
    struct DSU{ //合并:d[x]=d[y],查找:d[x]==d[y]
    	int a[N];
    	void init(int n){iota(a,a+n+1,0);}
    	int &operator[](int x){
    		return a[x]==x?a[x]:(a[x]=(*this)[a[x]]);
    	}
    }d;
    ll ans=0;
    int n,cnt[N],vis[N];
    int getcnt(int x){
    	if(vis[x])return 1;
    	vis[x]=1;
    	return cnt[x];
    }
    int connect(int x,int p){
    	x=d[x]; p=d[p]; if(x==p)return 0;
    	d[x]=p;
    	return getcnt(x)+getcnt(p)-1;
    }
    signed main(){
    	ios_base::sync_with_stdio(0); cin.tie(0);
    	cin>>n;
    	d.init(N-1);
    	repeat(i,0,n){
    		int x; cin>>x;
    		cnt[x]++;
    		ans-=x;
    	}
    	cnt[0]++;
    	repeat_back(s,0,N)
    	for(int x=s;x;x=(x-1)&s){ //遍历子集
    		int p=s^x; //x,p可以互相邀请,他们的边权为s
    		if(cnt[x] && cnt[p]){
    			ans+=(ll)s*connect(x,p);
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    深入浅出Blazor webassembly之程序配置
    深入浅出Blazor webassembly之通过CascadingValue组件实现向子级组件传值
    深入浅出Blazor webassembly之数据绑定写法
    深入浅出Blazor webassembly之浏览器WSAM性能测试
    重构的秘诀:消除重复,清晰意图
    在多数据源中对部分数据表使用shardingsphere进行分库分表
    logstach http input
    Addax 备忘
    WIN10下面0x00000bcb共享打印机无法连接怎么办?
    Calcite(二): 从list到tree的转换1
  • 原文地址:https://www.cnblogs.com/axiomofchoice/p/12408883.html
Copyright © 2011-2022 走看看