Codeforces Round #538 (Div. 2)

A.Got Any Grapes?

题意:
由三个人,第一个人需要x个a葡萄,第二个人需要y个a葡萄或b葡萄,第三个人需要z个a,b,c葡萄。问能否分配。
题解:
模拟一下即可。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 100005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}

int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int x,y,z,a,b,c;
	cin>>x>>y>>z>>a>>b>>c;
	if(a<x){
		cout<<"NO\n";
		return 0;
	}
	a-=x;
	if(a+b<y){
		cout<<"NO\n";
		return 0;
	}
	c+=a+b-y;
	if(c<z){
		cout<<"NO\n";
	}
	else cout<<"YES\n";
    return 0;
}

B. Yet Another Array Partitioning Task

题意:
有n个数,要你分成k段连续的子段,每个字段大于m个数。每个子段的值为子段中m个最大的数的和,问要怎么分配使得k个子段的和最大。
题解:
显然和最大时应该选择n个数中k最大的km个数。将最大km个数标记。没遇到m个数就分割成一段,一共k段。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 200005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
struct node{
	int num,id;
	bool operator<(const node&a){
		return num>a.num;
	}
}a[maxn];
int vis[maxn];
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	ll n,m,k;
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)cin>>a[i].num,a[i].id=i;
	sort(a+1,a+1+n);
	ll sum=0;
	for(int i=1;i<=k*m;i++)sum+=a[i].num,vis[a[i].id]=1;
	cout<<sum<<"\n";
	ll now=0;
	for(int i=1,kk=1;i<=n&&kk<k;i++){
		if(vis[i])now++;
		if(now==m)cout<<i<<" ",kk++,now=0;
	}
    return 0;
}

C. Trailing Loves (or L’oeufs?)

题意:
问n!转化为b进制末尾有多少个连续的0.
题解:
末尾连续的0的个数就等价于n!的因子中有多少个b。将b质因子拆分。对每个质因子求解n!中有多少个此质因子。答案显然为n中有多少个数为质因子p的倍数+pp的倍数+pp*p的倍数。。。 a n s = n p + n p 2 + . . . ans=\frac{n}{p}+\frac{n}{p^2}+... ans=pn+p2n+...
此过程用除法模拟,因为乘法会溢出。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 200005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}

int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	ll n,m;
	cin>>n>>m;
	vector<pair<ll,ll> >num;
	for(ll i=2;i*i<=m;i++){
		if(m%i==0){
			ll res=0;
			while(m%i==0)m/=i,res++;
			num.push_back(make_pair(i,res));
		}
	}	
	if(m>1)num.push_back(make_pair(m,1));
	ll ans=inf;
	for(auto &it:num){
		ll prime=it.first,siz=it.second;
		ll res=0;
		ll nn=n;
		while(nn){
			res+=nn/prime;
			nn/=prime;
		}
		ans=min(ans,res/siz);
	}
	cout<<ans;
    return 0;
}

D. Flood Fill

题意:
你可以将一段连续的相同颜色的连通块变成左边或右边不同的颜色,问最少多少次可以变成全部相同颜色。
题解:
很容易想到区间dp,枚举区间长度,每次大区间都由小区间+1转移而来。由于有左右两种方式,我们用dp[i][j][0/1]来表示,0表示颜色为c[i],1表示颜色为c[j]。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 200005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
int c[5555];
int dp[5555][5555][2];
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>c[i];
	memset(dp,INF,sizeof dp);
	for(int i=1;i<=n;i++)dp[i][i][0]=dp[i][i][1]=0;
	for(int len=1;len<=n;len++){
		for(int i=1;i+len-1<=n;i++){
			int j=i+len-1;
			dp[i-1][j][0]=min(dp[i-1][j][0],dp[i][j][1]+(c[i-1]!=c[j]));
			dp[i-1][j][0]=min(dp[i-1][j][0],dp[i][j][0]+(c[i-1]!=c[i]));
			dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][0]+(c[i]!=c[j+1]));
			dp[i][j+1][1]=min(dp[i][j+1][1],dp[i][j][1]+(c[j]!=c[j+1]));
		}
	}
	cout<<min(dp[1][n][0],dp[1][n][1]);
    return 0;
}

E. Arithmetic Progression

题意:
有一个打乱循序的等差数列,在60次内询问处最小值和公差D。
你可以询问“? i”询问a[i]的值。或者询问"> x"是否存在大于x的数。
题解:
首先我们询问最大值,最大值二分询问,需要30次询问。还剩下30次询问。我们可以随便选30个数,这30个数和最大值可以形成31个数,就会有30个差,30个差取gcd就可以确定公差D。但是只能询问30次,必须要31个不同的数,所以只能随机冲,只要随机出30个和最大值不同的值就能过。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 200005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
ll getmax(){
	ll l=0,r=1000000000;
	ll ans;
	while(l<=r){
		int mid=(l+r)>>1;
		cout<<"> "<<mid<<endl;
		ll res;
		cin>>res;
		if(res==1)l=mid+1;
		else r=mid-1,ans=mid;
	}
	return ans;
}
vector<ll>a;
ll n,maxx;
ll getd(){
	ll index=1;
	for(int i=1;i<=30;i++){
		index=rand()%(n-index+1)+index;
		cout<<"? "<<index<<endl;
		int x;
		cin>>x;
		a.push_back(x);
	}
	ll g=0;
	for(int i=0;i<a.size();i++)g=__gcd(g,maxx-a[i]);
	return g;
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	srand(int(time(0)));
	cin>>n;
	maxx=getmax();
	ll d=getd();
	cout<<"! "<<maxx-(n-1)*d<<" "<<d<<endl;
    return 0;
}//cnm

F. Please, another Queries on Array?

题意:
你有n个数。有q次询问。2个操作,第一个操作为l->r区间内的数都乘以x,第二个操作问l->r区间的乘积的欧拉函数值。
题解:
由于a[i]<=300,300内的质数只有62个,对62个数进行状压,用线段树维护区间乘积和区间状压的值,最后再算一下欧拉函数就行了。全部数据都要开longlong,防止溢出。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <map>
#include <string>
#include <stack>
#include <cctype>
#include <vector>
#include <queue>
#include <set>
#include <utility>
#include <cassert>
#include <iomanip>
#include <deque>
#include <time.h>
#include <bitset>
using namespace std;
#define ll long long
#define maxn 400005
#define mod 1000000007
#define MOD 998244353
#define Mod 1000000009
#define eps 1e-10
const ll inf=0x3f3f3f3f3f3f3f3f;
const ll INF=0x3f3f3f3f;
const ll mod1=1e9+7;
const ll mod2=1e9+9;
template <typename T>
inline void read(T& X) {X = 0; int w = 0; char ch = 0;while (!isdigit(ch)) { w |= ch == '-'; ch = getchar(); }while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();if (w) X = -X;}
char F[200];inline void write(int x){if(x == 0){putchar('0');return;}int tmp = x > 0 ? x : -x;int cnt = 0;if(x < 0)putchar( '-' );while(tmp > 0){F[cnt++] = tmp % 10 + '0';tmp /= 10;}while(cnt > 0)putchar(F[--cnt]) ;}
template<typename T> void print(T x){if(x>9) print(x/10);putchar(x%10+'0');}
ll q_pow(ll x,ll y,ll M){ll ans=1;while(y){if(y%2){y--;ans=ans*x%M;}else {y/=2;x=x*x%M;}}return ans;}
ll n,q;
ll a[maxn];
ll inv[100];
struct node{
	ll lazy,lazypos;
	ll sum,pos;
}tree[maxn<<2];
vector<ll>prime;
void init(){
	for(int i=2;i<=300;i++){
		int f=1;
		for(int j=2;j*j<=i;j++){
			if(i%j==0){
				f=0;
				break;
			}
		}
		if(f)prime.push_back(i);
	}
	for(ll i=0;i<62;i++)inv[i]=q_pow(prime[i],mod-2ll,mod);
}
void pushdown(int id,int l,int r){
	if(!tree[id].lazypos&&tree[id].lazy==1)return;
//	cout<<"??????pushdown "<<l<<" "<<r<<"\n";
	int mid=(l+r)>>1;
	tree[id<<1].lazy*=tree[id].lazy;tree[id<<1|1].lazy*=tree[id].lazy;
	tree[id<<1].lazy%=mod;tree[id<<1|1].lazy%=mod;
	tree[id<<1].sum=(tree[id<<1].sum*q_pow(tree[id].lazy,mid-l+1,mod))%mod;
	tree[id<<1|1].sum=(tree[id<<1|1].sum*q_pow(tree[id].lazy,r-mid,mod))%mod;
	tree[id<<1].pos|=tree[id].lazypos;tree[id<<1].lazypos|=tree[id].lazypos;
	tree[id<<1|1].pos|=tree[id].lazypos;tree[id<<1|1].lazypos|=tree[id].lazypos;
	tree[id].lazy=1;tree[id].lazypos=0;
	return;
}
node pushup(node a,node b){
	node c;
	c.sum=a.sum*b.sum%mod;
	c.pos=a.pos|b.pos;
	return c;
}
void build(int id,int l,int r){
	tree[id].lazy=1;
	if(l==r){
//		tree[id].lazy=1;
		tree[id].lazypos=0;
		tree[id].sum=a[l];
		ll res=0;
		for(int i=0;i<62;i++){
			if(a[l]%prime[i]==0){
				res+=(ll)(1ll<<i);
			}
		}
		tree[id].pos=res;
//		cout<<res<<" "<<a[l]<<" "<<l<<"----->\n";
		return ;
	}
	int mid=(l+r)>>1;
	build(id<<1,l,mid);
	build(id<<1|1,mid+1,r);
	tree[id].sum=tree[id<<1].sum*tree[id<<1|1].sum%mod;
	tree[id].pos=tree[id<<1].pos|tree[id<<1|1].pos;
}
void update(int id,int l,int r,int lx,int ly,ll val){
	if(l>=lx&&r<=ly){
		ll res=0;
		for(int i=0;i<62;i++){
			if(val%prime[i]==0){
				res+=(ll)(1ll<<i);
			}
		}
		tree[id].pos|=res;
		tree[id].lazypos|=res;
		tree[id].sum=(tree[id].sum*q_pow(val,(r-l+1),mod))%mod;
		tree[id].lazy=tree[id].lazy*val%mod;
		return ;
	}
	int mid=(l+r)>>1;
	pushdown(id,l,r);
	if(mid>=lx)update(id<<1,l,mid,lx,ly,val);
	if(mid<ly)update(id<<1|1,mid+1,r,lx,ly,val);
	tree[id].sum=tree[id<<1].sum*tree[id<<1|1].sum%mod;
	tree[id].pos=tree[id<<1].pos|tree[id<<1|1].pos;
}
node query(int id,int l,int r,int lx,int ly){
	if(l>=lx&&r<=ly){
		return tree[id];
	}
	int mid=(l+r)>>1;
	pushdown(id,l,r);
	node a,b;
	int f1=0,f2=0;
	if(mid>=lx)a=query(id<<1,l,mid,lx,ly),f1=1;
	if(mid<ly)b=query(id<<1|1,mid+1,r,lx,ly),f2=1;
	tree[id].sum=tree[id<<1].sum*tree[id<<1|1].sum%mod;
	tree[id].pos=tree[id<<1].pos|tree[id<<1|1].pos;
	if(f1&&f2)return pushup(a,b);
	if(f1)return a;
	if(f2)return b;
}
ll qu(node x){
	ll ans=x.sum;
//	cout<<x.pos<<"\n";
	for(ll i=0;i<62;i++){
		if((ll)(x.pos>>i)&1ll){
			ans=ans*(prime[i]-1ll)%mod*inv[i]%mod;
		}
	}
	return ans;
}
int main() 
{
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin>>n>>q;
	for(ll i=1;i<=n;i++)cin>>a[i];
	init();
	build(1,1,n);
//	cout<<tree[1].sum<<" "<<tree[1].pos<<"\n";
//	cout<<tree[2].sum<<" "<<tree[2].pos<<"\n";
//	cout<<query(1,1,n,1,2).sum<<"\n"; 
	string s;
	for(ll i=1,l,r,x;i<=q;i++){
		cin>>s;
		if(s=="TOTIENT"){
			cin>>l>>r;
			cout<<qu(query(1,1,n,l,r))<<"\n";
		}
		else {
			cin>>l>>r>>x;
			update(1,1,n,l,r,x);
		}
	}
//	for(int i=1;i<=n;i++){
//		cout<<query(1,1,n,i,i).sum<<"\n";
//	}
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值