Codeforces Round #538 (Div. 2)
根据题意模拟就好。
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 }
然后加了个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 }
这个就是个入门的区间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 }
E.Arithmetic Progression(交互题)
题意:
存在一个打乱顺序的n个数的等差数列。你要通过最多60次询问,得到这个等差数列的d和a1,也就是公差和最小的值。
询问有两种
1. ? i,询问第i个元素是什么
2. > x,询问是否存在严格大于x的值
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; }
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 }