Codeforces Round 900 (Div. 3)(A-F)

A. How Much Does Daytona Cost?

签到,只要有k就行

#include <bits/stdc++.h>

using namespace std;
const int N = 3e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;

void solve()
{
    int n,c;
    cin>>n>>c;
    vector<int> a(n+5);
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        if(a[i]==c) {
            cout<<"YES"<<endl;
            return ;
        }
    }
    cout<<"NO"<<endl;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    t = 1;
    cin>>t;
    while (t--)
    {
        solve();
    }
    system("pause");
    return 0;
}

B. Aleksa and Stack

思路:按照奇数序列构造即可,即 1 , 3 , 5 ⋯ n ∗ 2 − 1 1,3,5 \cdots n*2-1 1,3,5n21这种构造方法。
证明:因为所有数都是奇数,对于 a i , a i + 1 , a i + 2 a_i,a_{i+1},a_{i+2} ai,ai+1,ai+2而言, a i + a i + 1 a_i+a_{i+1} ai+ai+1为偶数, a i + 2 × 3 a_{i+2}\times3 ai+2×3依旧为奇数,偶数不能被奇数整除,原式得证。

#include <bits/stdc++.h>

using namespace std;
const int N = 3e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;


void solve()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cout<<i*2-1<<" ";
    }
    cout<<endl;

}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    t = 1;
    cin>>t;
    while (t--)
    {
        solve();
    }
    system("pause");
    return 0;
}

C. Vasilije in Cacak

思路:若给定的 x x x小于前 k k k个或者大于后 k k k个,那么则一定不合法。否则一定可以通过相关替换拼凑出该数。

#include <bits/stdc++.h>

using namespace std;
const int N = 3e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;

void solve()
{
    ll n,k,x;
    cin>>n>>k>>x;
    ll c1=(1+k)*k/2;
    if(x<c1){
        cout<<"NO"<<endl;
        return ;
    }
    ll c2=(n-k+1+n)*k/2;
    if(x>c2){
        cout<<"NO"<<endl;
        return ;
    }
    cout<<"YES"<<endl;

}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    t = 1;
    cin>>t;
    while (t--)
    {
        solve();
    }
    system("pause");
    return 0;
}

D. Reverse Madness

思路:我们可以发现,所有区间都是不相交的,每次进行的翻转操作,即是对于 [ l , r ] [l,r] [l,r]的区间,以 x x x为边界,以区间中心为对称轴进行翻转。所以具体怎么翻转我们并不关系,我们只用记录每个点的翻转次数即可。

#include <bits/stdc++.h>

using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 1e9+7;
const int maxv = 4e6 + 5;



void solve()
{	
	int n,k;
	cin>>n>>k;
	string s;
	cin>>s;
	vector<int> a(k+5),b(k+5),d(n+5);
	for(int i=1;i<=k;i++) cin>>a[i];
	for(int i=1;i<=k;i++) cin>>b[i];
	s=" "+s;
	int q;
	cin>>q;
	for(int i=1;i<=q;i++){
		int x;
		cin>>x;
		int loc=(lower_bound(b.begin()+1,b.begin()+k+1,x)-b.begin());//用二分去找x所在的区间
        int l=min(x,a[loc]+b[loc]-x);
        int r=max(x,a[loc]+b[loc]-x);
		d[l]++,d[r+1]--;//进行差分
	}
	for(int i=1;i<=n;i++) d[i]+=d[i-1];
	for(int i=1;i<=k;i++){
		int l=a[i],r=b[i];//对给定的k个区间进行遍历
		for(int j=l;j<=(l+r)/2;j++){//因为翻转前半部分和后半部分是等价的,所以只用计算前半部分
			if(d[j]%2){//如果当前点的翻转次数为奇数次
				swap(s[j],s[r-(j-l)]);
			}
		}
	}
	for(int i=1;i<=n;i++) cout<<s[i];
	cout<<endl;
}

int main()
{
    ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	t=1;
	cin>>t;
	while(t--){
		solve();
	}
    system("pause");
    return 0;
}

E. Iva & Pav

思路:st表维护区间与,因为与运算只会越与越小,所以可以用二分去维护能到达的最右端点。对于区间的维护,不一定需要使用st表,线段树,前缀和均可。

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;


int f[N][30];

int query(int l,int r)
{
    int len=__lg(r-l+1);
    int ans=f[l][len]&f[r-(1<<len)+1][len];
    return ans;
}

void st()
{
    int n,q;    
    cin>>n;  
    vector<int> a(n+5);
    for(int i=1;i<=n;i++){
        int x;
        cin>>x;
        a[i]=x;
        f[i][0]=x;
    }
    for(int j=1;j<=25;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            f[i][j]=f[i][j-1]&f[i+(1<<(j-1))][j-1];
        }
    }
    cin>>q;
    for(int i=1;i<=q;i++){
        int l,k;
        cin>>l>>k;
        if(a[l] < k)
		{
			cout << -1 << ' ';
			continue;
		}
		int L = l, R = n;
        int ans=0;
        while(L<=R){
            int mid=(L+R)/2;
            int res=query(l,mid);
            if(res>=k) {
                ans=mid;
                L=mid+1;
            }
            else R=mid-1;
        }
        cout<<ans<<" ";
    }   
    cout<<endl;
}

void solve()
{
    st();

}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    t = 1;
    cin>>t;
    while (t--)
    {
        solve();
    }
    system("pause");
    return 0;
}

F. Vasilije Loves Number Theory

思路:
当且仅当 d ( n ) d(n) d(n)除以 n n n时才存在解。

证明:考虑数 n = p 1 α 1 ⋅ p 2 α 2 ⋯ p k α k n = p_1^{\alpha_1} \cdot p_2^{\alpha_2} \cdots p_k^{\alpha_k} n=p1α1p2α2pkαk的质因数分解,其中 p i p_i pi表示 i i ith质数, α i \alpha_i αi表示 i i ith质数的最高幂,使得 p i α i p_i^{\alpha_i} piαi除以 n n n。知道了这一点,我们就可以用下面的公式计算出 n n n的被除数: d ( n ) = ( α 1 + 1 ) ⋅ ( α 2 + 1 ) ⋯ ( α k + 1 ) d(n) = (\alpha_1+1) \cdot (\alpha_2+1) \cdots (\alpha_k+1) d(n)=(α1+1)(α2+1)(αk+1).

现在让我们考虑一下我们正在进行的运算。我们正在用数字 n n n 乘以一个与 n n n 没有公共质因数的数字 a a a (条件 g c d ( a , n ) = 1 gcd(a, n) = 1 gcd(a,n)=1)。(条件 g c d ( a , n ) = 1 gcd(a, n) = 1 gcd(a,n)=1)。

n n n乘以任何与 n n n没有公共质因数的数字都只会给 n n n带来新的质因数,因此, d ( n ) d(n) d(n) 永远是数字 d ( n ⋅ a ) d(n\cdot a) d(na) 的被除数。因此,我们可以写出 d ( n ⋅ a ) = v ⋅ d ( n ) d(n \cdot a) = v \cdot d(n) d(na)=vd(n)。任选一个不是 n n n 因数的素数 p p p(这样的素数是存在的,因为素数的个数是无限的,而 n n n 的素数因数是有限的)。用 n n n乘以 a = p k − 1 a = p^{k-1} a=pk1,得到 d ( n ⋅ a ) = d ( n ) ⋅ k = n d(n\cdot a) = d(n) \cdot k = n d(na)=d(n)k=n

我们可以预处理出每个小于 1 0 6 10^6 106 的正整数的最小质因数。这样,我们就能在对数时间内对所有小于或等于 1 0 6 10^6 106的数字进行因式分解。我们还利用上述公式对 n n n进行因式分解并找出其除数个数,然后为每个质因数存储其仍能整除 n n n的最高幂次。我们都把这个结构称为 p o w e r power power

现在我们需要处理查询:

对于类型 2 的查询,我们只需重置所有内容。

对于第一个查询,我们在 O ( log ⁡ x ) \mathcal{O}(\log{x}) O(logx) 运算中对 x x x 进行因式分解,并让 x = r 1 β 1 ⋅ r 2 β 2 ⋯ r ℓ β ℓ x = r_1^{\beta_1} \cdot r_2^{\beta_2} \cdots r_\ell^{\beta_\ell} x=r1β1r2β2rβ 成为数字 x x x 的因式分解。我们通过以下操作更新 d ( n ) d(n) d(n):对于 x x x中的每个素数 r i r_i ri,用 d ( n ) d(n) d(n)除以 p o w e r [ r i ] + 1 power[r_i]+1 power[ri]+1,然后将 β i \beta_i βi加到 p o w e r [ r i ] power[r_i] power[ri],再用 d ( n ) d(n) d(n)乘以 p o w e r [ r i ] + 1 power[r_i]+1 power[ri]+1。计算出 d ( n ) d(n) d(n)后,我们应该检查 n n n是否能被它整除。我们可以用两种方法来做这件事:

因为 d ( n ) d(n) d(n)不会超过 1 0 9 10^9 109,但是 n n n的范围会很大很大,我们无法使用long long类型存下,我们考虑换一种存法,即对 n n n进行质因数分解,用 n = r 1 β 1 ⋅ r 2 β 2 ⋯ r ℓ β ℓ n = r_1^{\beta_1} \cdot r_2^{\beta_2} \cdots r_\ell^{\beta_\ell} n=r1β1r2β2rβ这种形式储存,具体使用map或者vector进行维护都可以。
对于检查是否能被 n n n整除,对于我们计算出的每一个值 m u l mul mul,我们让这个值去对 n n n的所有质因子进行遍历,若最终能够变成1,那么就代表肯定能够整除,因为 n n n若是能够整除 m u l mul mul,那么代表n的每一个质因子的个数肯定是大于等于 m u l mul mul质因子的个数的,只要最终 m u l mul mul能变为 1 (注,此时不一定需要把 n n n的因子全部耗尽),那么肯定合法。

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;

const int MAX = 1e6;
int f[MAX+5];
int prime[MAX+5];
int st[MAX+5];
int cnt=0;
void ol()//欧拉筛预处理每个数的最小因子
{
    int i,j;
    for(i=2;i<=MAX;i++){
        if(!st[i]){
            prime[cnt++]=i;
            f[i]=i;
        }
        for(j=0;i*prime[j]<=MAX&&j<cnt;j++){
            st[i*prime[j]]=1;
            f[i*prime[j]]=prime[j];
            if(i%prime[j]==0){
                
                break;
            }
        }
    }
}
 
void solve()
{
    int n,q;
    cin>>n>>q;
    ll mul=1;
    map<int,int> mp;
    while(n>1){
        int p=f[n];
        while(n%p==0){
            mp[p]++;
            n/=p;
        }
    }
    for(auto [x,y]: mp){
        mul*=(y+1);
    }
    ll tar=mul;//记录一开始n的因子个数值
    auto init=mp;//记录一开始n的因子信息
    while(q--){
        int op;
        cin>>op;
        if(op==1){
            int x;
            cin>>x;
            //vector c=factor_small(x);
            while(x>1){//对于每一个x,在logx的时间复杂度内处理出其所有因子
                int p=f[x];
                if(x%p==0){
                    mul/=(mp[p]+1);
                while(x%p==0){
                    mp[p]++;
                    x/=p;
                }
                mul*=(mp[p]+1);
                }
            }
            ll c=mul;
            for(auto [a,b]: mp){//检验是否整除
                while(c%a==0&&b>0) {
                    c/=a;
                    b--;
                }
            }
            if(c==1) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
        }
        else{
            mul=tar;
            mp=init;
        }
    }
    cout<<endl;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int t;
    t = 1;
    cin>>t;
    ol();
    while (t--)
    {
        solve();
    }
    system("pause");
    return 0;
}
  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值