Codeforces Round #716 (Div. 2)ABCDE题解


题目链接

A.Perfectly Imperfect Array

题意:给你个序列判断子序列之积不是理想的平方数

所以在给你的一串数组里判断是否有一个不是平方数即可

#include<bits/stdc++.h>
#define ll unsigned long long
#define N 100005
using namespace std;
ll t, n, m, x, xx, sum;
int main() {
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--) {
        cin>>n;
        q=0;
        for(int i=1; i<=n; i++) {
            cin>>x;
            xx=sqrt(x);
            if(xx*xx==x) q++;//不能直接sqrt*sqrt好像会WA
        }
        if(q==n) cout<<"NO"<<endl;
        else cout<<"YES"<<endl;
    }
    return 0;
}
/*
2
3
1 5 4
2
100 10000
*/

B.AND 0, Sum Big

题意:给你n和k,创造一个长为n的数组,数组元素为[0,2^k-1],并且元素按位与全是0的不同数组个数

这题各种想组合数然后就掉分了
其实最大值是固定的,然后就是分配k-1个位置

#include<bits/stdc++.h>
#define ll unsigned long long
#define N 100005
using namespace std;
const ll M=1e9+7;
ll  n, m, k, t, sum;
ll ksm(ll a,ll p){ll res=1;while(p){if(p&1){res=res*a%M;}a=a*a%M;p>>=1;}return res;}
int main() {
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    cin>>t;
    while(t--) {
        cin>>n>>k;
        cout<<ksm(n, k)<<endl;
    }
    return 0;
}
/*
2
2 2
100000 20
*/

C.Product 1 Modulo N

题意:给你n,求长度范围为[1, n-1]的数组 所有数组元素相乘%n==1

其实也是猜的 假如有公因子的话 到最后乘积%n就==0了比如 6!%9=0 7!%9=0 7!%9=0 8!%9=0
所以就是不能放和n有公因子的数,不然乘积不与n互素,就不可能等于1;最后要特判一下n-1。
威尔逊定理 当且仅当n是素数 (n-1)!mod n=n-1
也可以dfs打表找规律少了哪些数

//AC代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6 + 9;
 ll n, m, t, q, a[N], cnt;
int main() {
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n;
	m=1;
	for(ll i=1; i<=n-1; i++) {
        if(i==n-1) if(m*i%n!=1) continue;
        if(__gcd(n, i)==1) {
            m*=i;
            m%=n;//忘记取余了掉大分
            a[++q]=i;
        }
	}
    cout<<q<<endl ;
    for(int i=1; i<=q; i++) {
        cout<<a[i]<<" \n"[i==q];
    }
	return 0;
}

//打表代码
ll n, m, t, q, a[N], cnt;
vector<int> v, res;
void dfs(ll s, ll now, ll en) {
	if(s==en) {
		if(now==1&& res.size()<v.size())//比原来的长并且取模为1就更新(题目要最长
			res=v;
		return;
	}
	dfs(s+1, now, en);//不取这个数
	for(int i=s ; i<en; i++) {
		v.push_back(i);
		dfs(i+1, now*i%en, en);//取这个数
		v.pop_back();
	}
}
int main(){
	cin>>n;
    for(int i=2 ; i<=n ; i++) {
		v.clear();
		res.clear();
		dfs(1, 1, i);
		cout <<i<<" : "<<res.size()<<endl;
		sort(res.begin(), res.end());
		for(auto x: res)
			cout<<x<< " ";
		cout<<endl;
	 }
    return 0;
}

D.Cut and Stick

比赛的时候也没看,看了也没想到最优的切法
题意:给你个 a a a数组和 q q q次询问。每次询问给你 l l l r r r;问把区间 [ l , r ] [ l , r] [l,r] 最少分为几段,使区间内出现最多次的数 s s s的次数 < = ( m + 1 ) / 2 <=(m+1)/2 <=(m+1)/2 m = r − l + 1 m=r-l+1 m=rl+1即区间长度。

最优的切分方法是将剩下的 m − f m − f mf元素搭配上 m − f + 1 m − f + 1 mf+1 s s s,其余的 s s s切分成单个数的序列。共需要 1 + f − ( m − f + 1 ) = 2 f − m 1 + f − ( m − f + 1 ) = 2 f − m 1+f(mf+1)=2fm次。

莫队

lwhgg的题解

随机化算法(官方

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 10;
int a[N], n, q, l, r;
vector<int> G[N];
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int cnt(int k, int l, int r){
	return upper_bound(G[k].begin(), G[k].end(), r) - lower_bound(G[k].begin(), G[k].end(), l);
}//二分得数量
int solve(int l, int r){
	int ans = 1;
	for(int i=1; i<=30; i++){//好像说是2的-30次方的概率不被取到
		int pos=uniform_int_distribution<int>(l,r)(rng);//随机数 假定a[pos]是出现次数最大的那个数字
		ans=max(ans, 2*cnt(a[pos], l, r)-(r-l+1));//取最大值就是说明这次随机取得cnt比上次大因为长度r-l+1是固定的
	}
	return ans;
}
int main() {
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>q;
	for(int i=1; i<=n; i++){
		cin>>a[i];
		G[a[i]].push_back(i);//存位置
	}
	while(q--){
		cin>>l>>r;
		cout<<solve(l, r)<<endl;
	}
    return 0;
}

线段树维护出现最大的次数

复杂度 ( n l o g n ) (nlogn) (nlogn)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 10;
int a[N], n, q, l, r, tree[4*N];
vector<int> G[N];
int cnt(int k, int l, int r) {
	return upper_bound(G[k].begin(), G[k].end(), r) - lower_bound(G[k].begin(), G[k].end(), l);
}
void build(int p, int l, int r) {//建树
    if(l==r) {
        tree[p]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(2*p, l, mid);
    build(2*p+1, mid+1, r);
    tree[p]=(cnt(tree[2*p], l, r)>cnt(tree[2*p+1], l, r)? tree[2*p]:tree[2*p+1]);
}
int query(int p, int l, int r, int x, int y) {//查询
    if(y<x|| r<x|| l>y) return 0;//看清楚
	if(l>=x&&r<=y) return cnt(tree[p], x, y);//看清楚
	int mid=(l+r)>>1;
	return max(query(2*p, l, mid, x, y), query(2*p+1, mid+1, r, x, y));
}
int solve(int l, int r) {
	int f=query(1, 1, n, l, r);
	return max(1, 2*f-(r-l+1));
}
int main() {
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n>>q;
	for(int i=1; i<=n; i++) {
		cin>>a[i];
		G[a[i]].push_back(i);//存位置
	}
	build(1, 1, n);
	while(q--) {
		cin>>l>>r;
		cout<<solve(l, r)<<endl;
	}
    return 0;
}
/*6 2
1 3 2 3 3 2
1 6
2 5
*/

E.Baby Ehab’s Hyper Apartment

没看 不会 骗访客的


好像有题解了
官方题解

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值