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;
}