Codeforces Round #538 (Div. 2)(solve6/6)

题目链接:https://codeforces.com/contest/1114

A题

题意: 三个人分别至少选x,y,z件物品,有三种物品数量分别为a,b,c,其中第一个人只能选第一种,第二个人不能选第三种,第三个人随意问能否满足三个人需求。

思想: 模拟

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() 
{
    ll x,y,z;
	ll a,b,c; 
	cin>>x>>y>>z;
	cin>>a>>b>>c;
	if(a>=x && b+(a-x)>=y && b+(a-x)-y+c>=z)
		cout<<"YES\n";
	else
		cout<<"NO\n";
    return 0;
}

B题

题意:要求把n个数的数列分成k份,每份至少有m个数,问这k份的前m大数之和的和最大值是多少,并要求给出一种构造方案。
思想:先排序出来m*k个最大的,然后每m个前m*k最大的数分成一组。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>  P;
const int maxn = 2e5 + 10;
ll a[maxn];
int vis[maxn];
ll ans,num,num1,sum,n,m,k;
int main() 
{
    cin >> n >> m >> k;
    for(int i = 1; i <= n; i++) 
	{
        pair<int,int>p;
        cin >> p.first;
        p.second = i;
        q.push(p);
    }
    for(int i = 1; i <= m * k; i++) 
	{
        ans += q.top().first;
        vis[q.top().second] = 1;
        q.pop();
    }
    cout << ans << endl;
    for(int i = 1; i <= n; i++) 
	{
        num += vis[i];
        if(num==m && k>1) 
		{
			k--;
            cout <<i<<" ";
            num = 0;
        }
    }
    cout << endl;
    return 0;
}

C题

题意:给出 两个数n,b,n≤1e18,b≤1e12 问n!在b进制下有多少个后缀0

思想:考虑下,考虑下n!等于有多少可以凑出来b的倍数,然后考虑b可以由一些素因子构成,就变成了n!可以凑出来多少b的素因子。转换成n!由多少凑出来b的素因子,取一个最小值即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
ll a[maxn];
ll find(ll a,ll n)
{
	ll ans=0;
	while(n)
	{
		ans+=n/a;
		n=n/a;
	}
	return ans;
}
int main() 
{
    ll n,b,ans=1e18;
    scanf("%lld%lld",&n,&b);
	ll t=sqrt(b);
	for(ll i=2;i<=t;i++)
	{
		if(b%i==0)
		{
			ll cnt=0;
			while (b%i==0) 
			{
				++cnt;
				b /= i;
			}
			ans = min(ans,find(i,n)/cnt);
		}
	} 
	if(b>1)
		ans=min(ans,find(b,n));
	cout<<ans<<endl;
    return 0;
}

D 题

题意:给出一个n个数的数列(n≤5000),称一段相同的数为一个连通块,你每次可以选择一个连通块把它整体变成另一个数,问把整个数列变成同一个数的最少次数。
思想:DP转移,考虑等于左边界还是右边界。dp[i][j][0/1] 0代表i-j区间都等于a[i] 1代表i-j区间等于a[j] 

dp[i][j][0]可以由dp[i+1][j][0]+a[i]!=a[i+1]  和  dp[i+1][j][1]+a[i]!=a[j]

dp[i][j][1]可以由dp[i][j-1][0]+a[i]!=a[j]      和   dp[i][j-1][1]+a[j-1]!=a[j]

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5000+10;
int a[maxn];
int dp[maxn][maxn][2]; 
int main() 
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    	scanf("%d",&a[i]);
    for(int i=2;i<=n;i++)
    {
    	for(int l=1;l<=n;l++)
		{
			int r=l+i-1;
			if(r>n)
				break;
			dp[l][r][0]=min(dp[l+1][r][0]+int(a[l]!=a[l+1]),dp[l+1][r][1]+int(a[l]!=a[r]));
			dp[l][r][1]=min(dp[l][r-1][1]+int(a[r]!=a[r-1]),dp[l][r-1][0]+int(a[l]!=a[r]));
		}	
	}
    printf("%d\n",min(dp[1][n][0],dp[1][n][1]));
    return 0;
}

E 题

题意:给你一个长度为n的等差序列,现在打乱了,让你在60次交互次之内找到首项和等差。

思想:二分1-1e9 可以在30次的范围内找到最大值。然后随机选出来30个数和最大值的差值取gcd,就求出来了公差。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
map<ll,int>m;
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
int main()
{
	srand(time(0));
	ll n,l=0,r=1e9,flag,ans,cnt=0;
	cin>>n;
	while(l<=r)
	{
		ll mid=(l+r)/2;
		cout<<"> "<<mid<<endl<<endl;
		cin>>flag;
		if(flag)
			l=mid+1;
		else
			r=mid-1;
		cnt++;
	} 
	ans=l;
	ll s=0;
	for(int i=0;i<min(30ll,n);i++)
	{
		ll t;
		while(1)
		{
			t = rnd()%n+1;
			if(m.find(t)==m.end())
			{ 
				m[t]=1;
				break;
			}
		}	
		cout<<"? "<<t<<endl<<endl;
		cin>>t;
		s=__gcd(s,ans-t);
	}
	cout<<"! "<<ans-(n-1)*s<<" "<<s<<endl<<endl;
	
	return 0;
}

F题

题意:有两种操作,一个是区间乘x,一个是询问区间积的欧拉值。

思想:线段树和压位。县单数维护区间乘,然后考虑素数对于区间积的欧拉有影响,300之内就62个素数,将其压位到Long long,线段树维护乘的时候同时将X分解素因子,然后或上即可。

ps:别人2s就行我硬跑3s,感觉写丑了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+10;
const ll mod = 1e9+7;
struct node{
	int l,r;
	int valu;//值 
	int lazy;//懒惰乘积 
	ll mul1;//往下传递的 
	ll mul2;//自己的 
}no[maxn<<2];
int inv[305];
int f[65];
int s[65];//求出来300之内的素数
int vis[305];//标记素数 
int cnt;
void init()
{
	cnt=1;
	for(int i=2;i<=300;i++)
	{
		if(!vis[i])
		{
			s[cnt++]=i;
			for(int j=i+i;j<=300;j+=i)
				vis[j]=1;
		} 
	}
	inv[1]=1;
	for(int i=2;i<=300;i++)
		inv[i]=mod-1ll*(mod/i)*inv[mod%i]%mod;
    for(int i=1;i<cnt;i++)
		f[i]=1ll*inv[s[i]]*(s[i]-1)%mod;	
}
int qpow(int x,int y)
{
	int ans=1;
	while(y)
	{
		if(y&1)
			ans=(1ll*ans*x)%mod;
		x=(1ll*x*x)%mod;
		y=y>>1;
	}
	return ans;
}
void pushup(int id,node a,node b)
{
	no[id].valu=1ll*a.valu*b.valu%mod;
	no[id].mul2=1ll*a.mul2|b.mul2;
} 
void build(int id,int l,int r)
{
	no[id].l=l;
	no[id].r=r;
	no[id].lazy=1;
	no[id].mul1=0;
	no[id].mul2=0; 
	if(l==r)
	{
		scanf("%d",&no[id].valu);
		for(int i=1;i<cnt;i++)
			if(no[id].valu%s[i]==0)
				no[id].mul2|=(1ll<<(i-1));
		return ;
	}
	int mid=(l+r)/2;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	pushup(id,no[id<<1],no[id<<1|1]);
}
void pushdown(int id,ll x,ll y)
{
	if(no[id].lazy)
	{
		no[id<<1].lazy=(1ll*no[id<<1].lazy*x)%mod;
		no[id<<1|1].lazy=(1ll*no[id<<1|1].lazy*x)%mod;
		
		no[id<<1].mul1|=y;
		no[id<<1|1].mul1|=y;
		
		no[id<<1].mul2|=y;
		no[id<<1|1].mul2|=y;
		
		no[id<<1].valu=(1ll*no[id<<1].valu*qpow(x,no[id<<1].r-no[id<<1].l+1))%mod;
		no[id<<1|1].valu=(1ll*no[id<<1|1].valu*qpow(x,no[id<<1|1].r-no[id<<1|1].l+1))%mod;
		
		no[id].lazy=1;
		no[id].mul1=0;
	}
}
void update(int id,int l,int r,ll x,ll y)
{
	if(no[id].l>=l && no[id].r<=r)
	{
		no[id].valu=(1ll*no[id].valu*qpow(x,no[id].r-no[id].l+1))%mod;
		no[id].mul1|=y;
		no[id].mul2|=y;
		no[id].lazy=(1ll*no[id].lazy*x)%mod;
		return ;
	}
	pushdown(id,no[id].lazy,no[id].mul1);
	int mid=(no[id].l+no[id].r)/2;
	if(l<=mid)
		update(id<<1,l,r,x,y);
	if(r>mid)
		update(id<<1|1,l,r,x,y);
	pushup(id,no[id<<1],no[id<<1|1]);
}
node query(int id,int l,int r)
{
	if(no[id].l>=l && no[id].r<=r)
	{
		return no[id];
	}
	pushdown(id,no[id].lazy,no[id].mul1);
	int mid=(no[id].l+no[id].r)/2;
	if(r<=mid)
		return query(id<<1,l,r);
	if(l>mid)
		return query(id<<1|1,l,r);
	node xx,yy;
	xx=query(id<<1,l,r);
	yy=query(id<<1|1,l,r);
	xx.valu=(1ll*xx.valu*yy.valu)%mod;
	xx.mul2=(1ll*xx.mul2|yy.mul2);
	return xx;
}
int main()
{
	init();
	int n,q,l,r;
	char str[20];
	scanf("%d%d",&n,&q);
	build(1,1,n);
	while(q--)
	{
		scanf("%s",str);
		scanf("%d%d",&l,&r);
		if(str[0]=='T')
		{
			node t = query(1,l,r);//区间积 
			ll ans=t.valu;
			for(int i=1;i<cnt;i++)
			{
				if(t.mul2&(1ll<<(i-1)))
					ans=1ll*ans*f[i]%mod;
			} 
			printf("%lld\n",ans);
		}
		else
		{
			int x;
			ll y=0;
			scanf("%d",&x);
			for(int i=1;i<cnt;i++)
				if(x%s[i]==0)
					y+=(1ll<<(i-1));
			update(1,l,r,x,y);
		}
	}
	return 0;
}

补题结束~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值