【CF】Codeforces Round #538 (Div. 2)
太可怕了,我以为我F题最后提交上去了,结果发现并没有orz orz orz
A题
水题模拟
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
int x,y,z;
int a,b,c;
int main() {
scanf("%d%d%d",&x,&y,&z);
cin>>a>>b>>c;
if(a>=x&&a+b>=x+y&&a+b+c>=x+y+z) puts("YES");
else puts("NO");
}
B题
大胆猜测只用取前m*k个数,打上标记分每k个分块就可以了
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#define int long long
using namespace std;
const int maxn = 4e5+5;
int n,m,k;
struct node{
int wz,zhi;
}z[maxn],now[maxn];
int tot;
bool cmp(node aa,node bb) {
return aa.zhi > bb.zhi;
}
bool ccp(node aa,node bb) {
return aa.wz < bb.wz;
}
main() {
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>z[i].zhi,z[i].wz = i;
sort(z+1,z+1+n,cmp);
int ans = 0;
for(int i=1;i<=m*k;i++) {
now[i] = z[i];
ans+=now[i].zhi;
}
sort(now+1,now+1+m*k,ccp);
cout<<ans<<endl;
for(int i=1;i<k;i++) {
printf("%I64d ",now[i*m].wz);
}
}
C题
求n!在b进制下末尾有多少个0
类似找10进制下一样的方法,如果b可以表示为p1^k1 * p2^k2 * p3^k3 那么为对于n!包含因数pi^ki最少的个数。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#define int long long
using namespace std;
int n,b;
int mi;
int CNT;
int zz;
void facgetnum(int o,int x) {
if(o<x) return;
CNT+=o/x;
if(CNT/zz>=mi) return;
facgetnum(o/x,x);
}
main() {
mi = 1e18;
cin>>n>>b;
for(int i=2;i*i<=b;i++) {
if(b%i==0) {
int o = 0;
while(b%i==0) o++,b/=i;
CNT = 0;
zz = o;
facgetnum(n,i);
mi = min(mi,CNT/o);
}
}
if(b>1) {
CNT = 0;
zz = 1;
facgetnum(n,b);
mi = min(mi,CNT);
}
cout<<mi;
}
D
选择一个初始点,同色的为一个块,每一次可以将包含起始点块的左或右的那个方块变色,问最少操作次数
将同色unique之后就是一个区间配对的问题了(区间同颜色配对之后可以节省一次,否则直接变就是颜色-1次)
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
int f[5005][5005];
int n;
int a[5005],b[5005],tot;
int main() {
cin>>n;
for(int i=1;i<=n;i++) {
cin>>a[i];
if(a[i]!=a[i-1]) b[++tot] = a[i];
}
for(int cd=2;cd<=tot;cd++) {
for(int l=1;l+cd-1<=tot;l++) {
int r = l+cd-1;
f[l][r] = max(f[l+1][r],f[l][r-1]);
if(b[l]==b[r]) f[l][r] = max(f[l][r],f[l+1][r-1]+1);
}
}
cout<<tot-f[1][tot]-1;
}
E 补
给出一个等差数列将其乱序,你有2种询问操作:
1.“? i",询问ai的值
2."> x",询问序列中是否有元素大于x
要在60次询问内询问出该序列的首项和公差
我们显然可以用30次(log n)找出序列最大值。对于序列公差,然后我们可以rand多次,找出30个数(以及最大值)。这样之后两两作差之后的最大公约数就是公差。这样就可以找到 首项最大值-(n-1)*d 和公差 d 了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n;
void fl() {
fflush(stdout);
}
int a[50];
int gcd(int a,int b) {
return !b?a:gcd(b,a%b);
}
int grd() {
return (rand()<<15)|rand();
}
int main() {
scanf("%d",&n);
srand(time(NULL)^n);
int o = 0;
for(int i=29;i>=0;i--) {
cout<<"> "<<min((int)1e9,o+(1<<i))<<endl;
fl();
int x; cin>>x;
if(x==1) o=min(o+(1<<i),(int)1e9);
}
o++;
for(int i=1;i<=30;i++) {
cout<<"? "<<grd()%n+1<<endl;
fl();
cin>>a[i];
}
sort(a+1,a+1+30);
int cnt = unique(a+1,a+1+30)-a-1;
int oyo = a[2]-a[1];
a[cnt+1] = o;
for(int i=2;i<cnt+1;i++) oyo = gcd(oyo,a[i+1]-a[i]);
cout<<"! "<<o-oyo*(n-1)<<' '<<oyo<<endl;
}
F
一个序列,区间乘c,或求区间[l,r],$ \varphi(\prod \limits_{i=l}^{r} a_i) $,c和区间初始值<=300.
可以想到,询问主要就是问区间的乘积和区间乘因数包含哪些质数,线段树裸题维护bitset(哪些质数)和区间乘就可以了。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#include<bitset>
using namespace std;
const int maxn = 4e5+5;
const int mod = 1e9+7;
int add(int x,int y){ x+=y; return x>=mod?x-mod:x; }
int sub(int x,int y){ x-=y; return x<0?x+mod:x; }
int mul(int x,int y){ return 1ll*x*y%mod; }
int ksm(int a,int b) {
int ans = 1;
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans = mul(ans,a);
return ans;
}
int n,q;
int cnt,pri[305],dy[305],lat[305]; bool mk[305];
void init() {
mk[0] = mk[1] = 1;
for(int i=2;i<=300;i++) {
if(!mk[i]) { pri[++cnt] = i; lat[i]=cnt; dy[cnt] = mul(ksm(i,mod-2),i-1); }
for(int j=1;j<=cnt&&1ll*pri[j]*i<=300;j++) {
int k = pri[j]*i;
mk[k] = 1;
lat[k] = j;
if(i%pri[j]==0) break;
}
}
}
struct node{
node *ls,*rs;
bitset<64>b,lab;
int mt,laz;
}z[maxn*2],*rt; int tot;
void upd(node *&p) {
p->b = p->ls->b|p->rs->b;
p->mt = mul(p->ls->mt,p->rs->mt);
}
void ptd(node *&p,int l,int mid,int r) {
p->ls->laz = mul(p->ls->laz,p->laz);
p->rs->laz = mul(p->rs->laz,p->laz);
p->ls->mt = mul(p->ls->mt,ksm(p->laz,mid-l+1));
p->rs->mt = mul(p->rs->mt,ksm(p->laz,r-mid));
p->ls->b |= p->lab; p->rs->b |= p->lab;
p->ls->lab |= p->lab; p->rs->lab |= p->lab;
p->laz = 1;
}
void maketree(node *&p,int l,int r) {
p = &z[++tot];
p->laz = 1;
if(l==r) {
int x; scanf("%d",&x);
p->mt = x;
while(x!=1) {
p->b[lat[x]] = 1;
x/=pri[lat[x]];
}
return;
}
int mid = (l+r)>>1;
maketree(p->ls,l,mid); maketree(p->rs,mid+1,r);
upd(p);
}
void upd(node *&p,int l,int r,int x,int y,int d) {
if(x<=l&&r<=y) {
p->mt = mul(p->mt,ksm(d,r-l+1));
p->laz = mul(p->laz,d);
while(d!=1) {
p->b[lat[d]] = 1;
p->lab[lat[d]] = 1;
d/=pri[lat[d]];
}
return;
}
int mid = (l+r)>>1;
ptd(p,l,mid,r);
if(y<=mid) upd(p->ls,l,mid,x,y,d);
else if(x>mid) upd(p->rs,mid+1,r,x,y,d);
else upd(p->ls,l,mid,x,y,d),upd(p->rs,mid+1,r,x,y,d);
upd(p);
}
bitset<64>bbb;
int query(node *&p,int l,int r,int x,int y) {
if(x<=l&&r<=y) {
bbb|=p->b;
return p->mt;
}
int mid = (l+r)>>1;
ptd(p,l,mid,r);
if(y<=mid) return query(p->ls,l,mid,x,y);
else if(x>mid) return query(p->rs,mid+1,r,x,y);
else return mul(query(p->ls,l,mid,x,y),query(p->rs,mid+1,r,x,y));
}
char ss[15];
int main() {
init();
scanf("%d%d",&n,&q);
maketree(rt,1,n);
int l,r,x;
for(int i=1;i<=q;i++) {
scanf("%s",&ss[1]);
if(ss[1]=='M') {
scanf("%d%d%d",&l,&r,&x);
upd(rt,1,n,l,r,x);
} else {
scanf("%d%d",&l,&r);
bbb.reset();
int ans = query(rt,1,n,l,r);
for(int i=1;i<=cnt;i++) {
if(bbb[i]) ans = mul(ans,dy[i]);
}
printf("%d\n",ans);
}
}
}