2018提高組模擬13
阿新 • • 發佈:2018-11-01
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; }