版权声明:小蒟蒻的博客转载也请注明出处哦 https://blog.csdn.net/qq_42835823/article/details/83503924
20181027
T1 洛阳怀
【WOJ4150】
素数线性筛
GCD
数学推理
多读几遍,不难发现:
- 如果我们除以了前i个的GCD,那么i以后的都不能除了
- 每个数的分数是它的好的质因数个数减去坏的质因数个数(打表可以发现)
所以我们记录一下每个数的好质因数的个数和坏质因数的个数,
再按记录一个前i个数的GCD的好质因数的个数和坏质因数的个数。
因为我们除以后面对前面是没有影响的,所以可以从后往前搜,
每次前i的GCD如果坏的多余好的就除掉,再同步记录一下lazy就好。
#include<iostream>
#include<cstdio>
#include<bitset>
#include<cctype>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x;
}
int t=0,pri[10000];
bitset<100010>c;
void find_prime(){
for(int i=2;i<=100000;i++){
if(!c[i])pri[++t]=i;
for(int j=1;j<=t&&i*pri[j]<=100000;j++){
c[i*pri[j]]=1;
if(i%pri[j]==0)break;
}
}
}
int n,m,a[2010],b[2010],h;
int hao[2010],huai[2010],so[2010],si[2010];
bitset<1000000005>g;
void divide(int u){
int x=a[u],j=1;
while(pri[j]*pri[j]<=x){
while(x%pri[j]==0){
x/=pri[j];
if(g[pri[j]])huai[u]++;
else hao[u]++;
}
j++;
}
if(x>1){
if(g[x])huai[u]++;
else hao[u]++;
}
}
int gcd(int x){
int r;
if(x>h){r=x;x=h;h=r;}
while(x){
r=x;
x=h%x;
h=r;
}
return h;
}
void divide_2(int x,int u){
int j=1;
while(pri[j]*pri[j]<=x){
while(x%pri[j]==0){
x/=pri[j];
if(g[pri[j]])si[u]++;
else so[u]++;
}
j++;
}
if(x>1){
if(g[x])si[u]++;
else so[u]++;
}
}
int main(){
n=read();m=read();
find_prime();
for(int i=1;i<=n;i++)
a[i]=read();
for(int i=1;i<=m;i++){
b[i]=read();
g[b[i]]=true;
}
h=a[1];divide(1);
so[1]=hao[1];si[1]=huai[1];
for(int i=2;i<=n;i++){
divide(i);
divide_2(gcd(a[i]),i);
}
int lazyo=0,lazyi=0,ans=0;
for(int i=n;i>0;i--){
so[i]-=lazyo;si[i]-=lazyi;
if(si[i]>=so[i]){
lazyo+=so[i];
lazyi+=si[i];
}
hao[i]-=lazyo;huai[i]-=lazyi;
ans+=(hao[i]-huai[i]);
}
printf("%d",ans);
return 0;
}
T2 洗衣服
【WOJ2796】
堆
贪心
可以用堆。
我们给每一台机器都安排一个任务。
然后每次取堆顶(最快做完的),再安排一个任务,入堆。
这样取出最快的L个,加入一个数组。
洗衣机和烘干机都一样。
然后,根据排序不等式
两台机器,最大的配最小,再取一个MAX就是答案了 ^ _ ^。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x;
}
#define ll long long
int n,m,k,a[100010],b[100010];
ll l1[1000010],l2[1000010];
priority_queue< pair<ll,int> >q1;
priority_queue< pair<ll,int> >q2;
int main(){
k=read();n=read();m=read();
for(int i=1;i<=n;i++){
a[i]=read();
q1.push(make_pair(-(ll)a[i],i));
}
for(int i=1;i<=m;i++){
b[i]=read();
q2.push(make_pair(-(ll)b[i],i));
}
for(int i=1;i<=k;i++){
int y1=q1.top().second;
ll x1=q1.top().first;q1.pop();
l1[i]=-x1;q1.push(make_pair(x1-a[y1],y1));
ll x2=q2.top().first;
int y2=q2.top().second;q2.pop();
l2[i]=-x2;q2.push(make_pair(x2-b[y2],y2));
}
ll ans=0;
for(int i=1;i<=k;i++){
ans=max(ans,l1[i]+l2[k-i+1]);
}
printf("%lld",ans);
return 0;
}
T3 成绩单
【WOJ3175】
区间DP
题解:%%%LDX%%%
最后应该是 +f[j+1][t]
不难发现,g 的第一位都没有变过,所以就强行压下了一维。
看完后,打一打代码,大概就懂了……
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x;
}
int n,m,a,b;
int c[60],h[60];
int f[55][55],g[55][55][55];
int main(){
n=read();a=read();b=read();
for(int i=1;i<=n;i++){
c[i]=h[i]=read();
f[i][i]=a;
}
sort(h+1,h+n+1);
int m=unique(h+1,h+n+1)-h-1;
for(int i=1;i<=n;i++)
c[i]=lower_bound(h+1,h+m+1,c[i])-h;
for(int len=2;len<=n;len++)
for(int l=1,r=len;r<=n;l++,r++){
for(int i=l;i<=r;i++)
for(int j=m;j;j--)
for(int k=m;k>=j;k--)
g[i][j][k]=1<<30;
g[l][c[l]][c[l]]=0;
for(int i=l;i<r;i++)
for(int j=m;j>0;j--)
for(int k=m;k>=j;k--){
if(g[i][j][k]==1<<30)continue;
int e=min(j,c[i+1]),d=max(k,c[i+1]);
g[i+1][e][d]=min(g[i+1][e][d],g[i][j][k]);
for(int t=r;t>i;t--)
g[t][j][k]=min(g[t][j][k],g[i][j][k]+f[i+1][t]);
}
f[l][r]=1<<30;
for(int j=m;j;j--)
for(int k=m;k>=j;k--)
f[l][r]=min(f[l][r],g[r][j][k]+a+b*(h[j]-h[k])*(h[j]-h[k]));
}
printf("%d",f[1][n]);
return 0;
}