Codeforces Round #538 (Div. 2)

A.Got Any Grapes?

根据题意模拟就好。

B.Yet Another Array Partitioning Task

题意:

给出一个大小为n的数组,把它分成k段,每一段最大的m个数字加起来和最大。

题解:

那么最好的答案就是这n个数里面最大的m*k个数都被取到。

C.Trailing Loves (or L'oeufs?)

题意

求n!在b进制下末尾的0的个数。其中n<=1e18,b<=1e12

题解:

模拟一下进制转换的过程我们发现,等价于求n!mod b^k=0的k的最大值。我们如果把n!和b都进行质因子分解,对于质数p,n!对于p的指数是b1,对于b的指数是b2,那么当b2不为0的时候,k=min(b1/b2).但是n!非常大,连求出来都不可能。那么我们可以把b因数分解,然后对于b的每一质因数,求出n!中这个质因数的质数。然后问题就只剩对于质数p,怎么求n!中p的指数。我们都知道n/p是求1-n中能被p整除的数的个数,就用这种方法求就好。注意容易爆longlong

我一开始那一段是这么写的然后一直wa

1 LL cal(LL n,LL p){//n!中质数p的指数
2     LL res=0;
3     LL num=p;
4     while(n/num>=1){
5         res+=n/num;
6         num=num*p;
7     }
8     return res;
9 }
View Code

然后加了个break就a了。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <cmath>
 6 
 7 using namespace std;
 8 const long long INF=1e18;
 9 const int maxn=100000;
10 typedef long long LL;
11 LL n,b;
12 LL prime[maxn];
13 int cnt,num[maxn];
14 void solve(LL x){
15     int m=sqrt(x);
16     for(int i=2;i<=m;i++){
17         if(x%i==0){
18             cnt++;
19             prime[cnt]=i;
20             while(x%i==0){
21                 num[cnt]++;
22                 x/=i;
23             }
24         }
25     }
26     if(x>1){
27         cnt++;
28         prime[cnt]=x;
29         num[cnt]++;
30     }
31 }
32 
33 LL cal(LL n,LL p){//n!中质数p的指数
34     LL res=0;
35     LL num=p;
36     while(n/num>=1){
37         res+=n/num;
38         if(num>n/p)break;
39         num=num*p;
40     }
41     return res;
42 }
43 
44 int main(){
45     scanf("%I64d%I64d",&n,&b);
46     solve(b);
47     LL ans=INF;
48     //LL c=cal(n,prime[1]);
49 
50     for(int i=1;i<=cnt;i++){
51         ans=min(ans,cal(n,prime[i])/num[i]);
52     }
53     printf("%I64d\n",ans);
54 return 0;
55 }
View Code

 D.Flood Fill

这个就是个入门的区间dp,记忆话很好写。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5 
 6 using namespace std;
 7 const int maxn=5000+10;
 8 const int INF=2147000000;
 9 int n;
10 int c[maxn];
11 int f[maxn][maxn];
12 int L[maxn],R[maxn];
13 int dp(int l,int r){
14     if(f[l][r])
15         return f[l][r];
16     if(l==1&&r==n)
17         return 0;
18     f[l][r]=INF;
19     if(c[l-1]==c[r+1]){
20         f[l][r]=min(f[l][r],dp(L[l-1],R[r+1])+1);
21     }else{
22         if(l>1)f[l][r]=min(f[l][r],dp(L[l-1],r)+1);
23         if(r<n)f[l][r]=min(f[l][r],dp(l,R[r+1])+1);
24     }
25     return f[l][r];
26 }
27 int main(){
28     scanf("%d",&n);
29     for(int i=1;i<=n;i++){
30         scanf("%d",&c[i]);
31         if(c[i]==c[i-1])
32             L[i]=L[i-1];
33         else L[i]=i;
34     }
35     for(int i=n;i>=1;i--){
36         if(c[i]==c[i+1])
37             R[i]=R[i+1];
38         else R[i]=i;
39     }
40 //    for(int i=1;i<=n;i++){
41 //        printf("%d %d %d\n",i,L[i],R[i]);
42 //    }
43     int ans=INF;
44     for(int i=1;i<=n;i++){
45         ans=min(ans,dp(L[i],R[i]));
46     }
47     printf("%d\n",ans);
48 return 0;
49 }
View Code

E.Arithmetic Progression(交互题)

题意:

存在一个打乱顺序的n个数的等差数列。你要通过最多60次询问,得到这个等差数列的d和a1,也就是公差和最小的值。
询问有两种
1. ? i,询问第i个元素是什么
2. > x,询问是否存在严格大于x的值
题解:
如果这个题是找最大值的话就很容易了,二分就可以了,最小值呢就用最大值减去n-1的公差就好了。问题是怎么求公差d呢?对于打乱顺序的a,|ai-ai-1|=di,那么di一定是公差d的倍数。那么我们随机拿出30个数来,排序然后求di,然后求这些di的gcd,得到的就是公差d。我不太会证明,只能靠猜···
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>

using namespace std;
const int maxn=1e6+100;

int gcd(int a,int b){
    if(!b)return a;
    return gcd(b,a%b);
}
int ask1(int x){
    printf("? %d\n",x);
    fflush(stdout);
    int res;
    scanf("%d",&res);
    return res;
}
int ask2(int x){
    printf("> %d\n",x);
    fflush(stdout);
    int res;
    scanf("%d",&res);
    return res;
}

int n,m;
int a[maxn];
int main(){
    srand(time(NULL));
    scanf("%d",&n);
    for(int i=1;i<=30;i++){
        int r=rand()*rand()%n+1;
        int x=ask1(r);
        a[++m]=x;
    }
    sort(a+1,a+1+m);
    int d=a[2]-a[1];
    for(int i=3;i<=m;i++)
        d=gcd(d,a[i]-a[i-1]);
    int l=0,r=1e9,ans=0;
    while(l<=r){
        int mid=l+(r-l)/2;
        if(ask2(mid)){
            l=mid+1;
        }else{
            ans=mid;
            r=mid-1;
        }
    }
    printf("! %d %d\n",ans-(n-1)*d,d);
return 0;
}
View Code

F:Please, another Queries on Array?

题意:给出一个n个数字的数组,和q个询问。

询问有两种
1."MULTIPLY l r x"
将[l,r]的m每个数都乘x
2."TOTIENT l r"
输出phi(al*al+1*...*ar)mod 1e9+7

题解:

我们要先回想一下欧拉函数的性质。

然后对于这个题

300以内只有62个,可以状态压缩,显然也可以用线段树维护。

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 #include <iostream>
  5 #include <cmath>
  6 
  7 using namespace std;
  8 typedef long long LL;
  9 const int maxn=4e5+10;
 10 const int mod=1e9+7;
 11 
 12 int n,q,sz;
 13 int a[maxn],prime[100],vis[400],pos[400];
 14 
 15 void init(){
 16     int m=sqrt(300);
 17     for(int i=2;i<=m;i++){
 18         if(!vis[i]){
 19             for(int j=i*i;j<=300;j+=i){
 20                 vis[j]=1;
 21             }
 22         }
 23     }
 24     for(int i=2;i<=300;i++){
 25         if(!vis[i]){
 26             prime[sz]=i;
 27             pos[i]=sz++;
 28         }
 29     }
 30 }
 31 LL qpow(int n,int k){
 32     LL res=1;
 33     while(k){
 34         if(k&1)res=res*n%mod;
 35         n=(LL)n*n%mod;
 36         k>>=1;
 37     }
 38     return res%mod;
 39 }
 40 LL mulv[4*maxn],prmv[4*maxn];
 41 LL tag_m[4*maxn],tag_p[4*maxn];
 42 LL solve(int x){
 43     LL res=0;
 44     int m=sqrt(x);
 45     for(int i=2;i<=m;i++){
 46         if(x%i==0){
 47             res|=(LL)(1ll<<pos[i]);
 48             while(x%i==0)
 49                 x/=i;
 50         }
 51     }
 52     if(x>1){
 53         res|=(LL)(1ll<<pos[x]);
 54     }
 55     return res;
 56 }
 57 
 58 void maintain(int o){
 59     int lc=2*o,rc=2*o+1;
 60     mulv[o]=mulv[lc]*mulv[rc]%mod;
 61     prmv[o]=prmv[lc]|prmv[rc];
 62 }
 63 
 64 void pushdown(int o,int L,int R){
 65     int lc=2*o,rc=2*o+1;
 66     if(tag_m[o]!=1){
 67         int M=L+(R-L)/2;
 68 
 69         mulv[lc]=qpow(tag_m[o],M-L+1)*mulv[lc]%mod;
 70         mulv[rc]=qpow(tag_m[o],R-M)*mulv[rc]%mod;
 71         tag_m[lc]=tag_m[o]*tag_m[lc]%mod;
 72         tag_m[rc]=tag_m[o]*tag_m[rc]%mod;
 73         tag_m[o]=1;
 74     }
 75     if(tag_p[o]){
 76         prmv[lc]|=tag_p[o];
 77         prmv[rc]|=tag_p[o];
 78         tag_p[lc]|=tag_p[o];
 79         tag_p[rc]|=tag_p[o];
 80         tag_p[o]=0;
 81     }
 82 }
 83 
 84 void build(int o,int L,int R){
 85     mulv[o]=tag_m[o]=1;
 86     prmv[o]=tag_p[o]=0;
 87     if(L==R){
 88         mulv[o]=a[L];
 89         prmv[o]=solve(a[L]);
 90         return ;
 91     }
 92     int M=L+(R-L)/2;
 93     build(2*o,L,M);
 94     build(2*o+1,M+1,R);
 95     maintain(o);
 96 }
 97 void update(int o,int L,int R,int ql,int qr,int v){
 98     if(ql<=L&&qr>=R){
 99         mulv[o]=mulv[o]*qpow(v,R-L+1)%mod;
100         tag_m[o]=tag_m[o]*v%mod;
101         LL S=solve(v);
102         tag_p[o]|=S;
103         prmv[o]|=S;
104         return;
105     }
106     int M=L+(R-L)/2;
107     pushdown(o,L,R);
108     if(ql<=M)update(2*o,L,M,ql,qr,v);
109     if(qr>M)update(2*o+1,M+1,R,ql,qr,v);
110     maintain(o);
111 }
112 LL ans_S,ans;
113 void query(int o,int L,int R,int ql,int qr){
114     if(ql<=L&&qr>=R){
115         ans=ans*mulv[o]%mod;
116         ans_S|=prmv[o];
117         return;
118     }
119     int M=L+(R-L)/2;
120     pushdown(o,L,R);
121 
122     if(ql<=M)query(2*o,L,M,ql,qr);
123     if(qr>M)query(2*o+1,M+1,R,ql,qr);
124     maintain(o);
125 }
126 void gcd(LL a,LL b,LL& d,LL& x,LL& y){
127     if(!b){
128         d=a;x=1;y=0;
129     }else{
130         gcd(b,a%b,d,y,x);
131         y-=x*(a/b);
132     }
133 }
134 LL inv(LL a,LL p){
135     LL d,x,y;
136     gcd(a,p,d,x,y);
137     if(d!=1)return -1;
138     return (x+p)%p;
139 }
140 void tra(int o,int L,int R){
141     printf("%d %d %d %I64d %I64d\n",o,L,R,mulv[o],prmv[o]);
142     if(L==R)return;
143     int M=L+(R-L)/2;
144     tra(2*o,L,M);
145     tra(2*o+1,M+1,R);
146 }
147 
148 int main(){
149     init();
150     scanf("%d%d",&n,&q);
151     for(int i=1;i<=n;i++){
152         scanf("%d",&a[i]);
153     }
154     build(1,1,n);
155    // tra(1,1,n);
156     for(int i=1;i<=q;i++){
157         string type;
158         cin>>type;
159         if(type=="TOTIENT"){
160             int ql,qr;
161             scanf("%d%d",&ql,&qr);
162             ans=1,ans_S=0;
163             query(1,1,n,ql,qr);
164             LL sum=1;
165             for(int j=0;j<62;j++){
166                 LL S=(LL)(1ll<<j);
167                 if(ans_S&S){
168                     sum=sum*(prime[j]-1)%mod*inv(prime[j],mod)%mod;
169                    // printf("@%d %I64d %I64d\n",prime[j],inv(prime[j],mod),inv(prime[j],mod)*prime[j]%mod);
170                 }
171             }
172             LL ANS=sum*ans%mod;
173             printf("%I64d\n",ANS);
174         }else{
175             int ql,qr,v;
176             scanf("%d%d%d",&ql,&qr,&v);
177             update(1,1,n,ql,qr,v);
178         }
179     }
180 return 0;
181 }
View Code

 

 

 

 

posted @ 2019-02-15 16:37  蒟蒻LQL  阅读(282)  评论(0编辑  收藏  举报