A Median
打了 \(70\) 分,但是因為 \(printf("%.1lf")\) 慘遭爆零。
原因詳見我寫的討論。
首先,你需要把 \([1,10^7]\) f範圍是質數全部篩出來,大概耗時半秒。
然後,考慮資料是根據質數構造的,所以近似為隨機。
那麼既然隨機,那咱們直接對於每次移動去維護中位數的位置就好了。
點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1.1e7+7,M=5e5+5,K=180000000;
//180000000
bitset<K>vis;
bitset<K>isp,p1;
int p[N];
int ccnt;
int ans;
inline void init(int n)
{
for(int i=2;i<=n;i++)
{
if(!vis[i]) p[++ccnt]=i;
for(int j=1;1ll*i*p[j]<=n;j++)
{
vis[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
}
int n,k,w;
int s[N],s2[N];
int sub[N];
const int mx=1e7;
int cnt[N];
namespace sub1{
inline void init2(int n)
{
for(int i=2;i<=n;i++)
{
if(!isp[i])
{
p1[++ccnt]=(i%3==2?1:0);
for(int j=2;j*i<=n;j++) isp[j*i]=1;
}
}
}
int c[6];
void Q()
{
init2(180000000);
p1[2]=0,p1[1]=2,s2[0]=5;
for(int i=1;i<=n;i++)
{
if(i==2)
{
s[i]=0,s2[i]=s[i/10+1];
continue;
}
s[i]=((p1[i]==1?2:1)*i)%w;
s2[i]=s[i]+s[i/10+1];
}
for(int i=0;i<k;i++)c[s2[i]]++;
double ans=0;
for(int i=1;i<=n-k+1;i++)
{
c[s2[i-1]]--,c[s2[i+k-1]]++;
if(k%2==1)
{
int mid=(k+1)/2,lcnt=0,j=0;
for(;j<=4;j++)
{
lcnt+=c[j];
if(lcnt>=mid) break;
}
ans+=j;
}
else
{
int mid=k>>1,lcnt=0,j=0;
double res=0;
for(;j<=4;j++)
{
lcnt+=c[j];
if(lcnt>mid)
{
res=j;break;
}
else if(lcnt==mid)
{
int k=j+1;
while(!c[k])k++;
res+=(double)(j+k)/2.0;
break;
}
}
ans+=res;
}
}
printf("%.1f",ans);
exit(0);
}
}
signed main()
{
freopen("median.in","r",stdin);
freopen("median.out","w",stdout);
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>k>>w;
if(w==3)sub1::Q();
init(180000000);
for(int i=1;i<=n;i++)
s[i]=(p[i]*i%w),s2[i]=s[i]+s[i/10+1];
for(int i=1;i<=k;i++) cnt[s2[i]]++;
if(k&1)
{
int sum=0,tp1=0,tp2=0,cnt1=0,cnt2=0;
for(int i=1;i<=mx;i++)
{
sum+=cnt[i];
if(sum>=k/2+1)
{
cnt1=sum-cnt[i],cnt2=k-sum;
tp1=tp2=i;
break;
}
if(cnt[i]) tp1=i;
}
ans+=tp1+tp2;
int num=k/2;
for(int i=1;i<=n-k;i++)
{
int lst=s2[i],now=s2[i+k];
cnt[lst]--,cnt[now]++;
cnt1+=-(lst<tp1)+(now<tp1);
cnt2+=-(lst>tp1)+(now>tp1);
while(cnt1>num)
cnt2+=cnt[tp1],tp1--,cnt1-=cnt[tp1];
while(cnt2>num)
cnt1+=cnt[tp1],tp1++,cnt2-=cnt[tp1];
ans+=tp1*2;
}
}
else
{
int num=k/2,cnt1=0,cnt2=0;
int tp1=-1,tp2=-1;
for(int i=k;i<=n;i++)
{
if(i!=k) cnt[s2[i]]++;
if(s2[i]<=tp1) cnt1++;
if(s2[i]<=tp2) cnt2++;
if(i>k)
{
cnt[s2[i-k]]--;
if(s2[i-k]<=tp1) cnt1--;
if(s2[i-k]<=tp2) cnt2--;
}
while(cnt1<num) cnt1+=cnt[++tp1];
while(cnt2<=num) cnt2+=cnt[++tp2];
while(cnt1>=num+cnt[tp1]) cnt1-=cnt[tp1--];
while(cnt2>=num+1+cnt[tp2]) cnt2-=cnt[tp2--];
ans+=tp1+tp2;
}
}
if(ans&1) cout<<ans/2<<".5";
else cout<<ans/2<<".0";
}
B Game
太可惡了。考場上差點打出來,結果忽然不想打了,痛失 50。
\(\log\) 做法是顯然的。拿優先佇列每次取出隊頭久好了。
但是 \(O(nk\log n)\) 不能接受啊。
那其實我們可以從值域下手。
維護最大值,每次暴力地看最大值是否被修改,如果修改,則更新最大值。
這時候最大值只可能是被取走,因為如果當前值比最大值還要大,那麼你會優先取走這個。
因此,序列中維護的最大值是單調不增的。
那我們維護一次就是 \(O(n)\),總複雜度 \(O(nk)\)。
點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
const int N=1e6+6;
int a[N], t[N];
signed main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
while(k--)
{
int cnta=0,cntb=0;
int p;cin>>p;
int mx=0;
for(int i=1;i<p;i++) t[a[i]]++,mx=max(mx,a[i]);
int stp=0;
for(int i=p;i<=n;i++)
{
stp++;
if(a[i]>=mx) stp%2==1?cnta+=a[i]:cntb+=a[i];
else
{
t[a[i]]++,t[mx]--;
(stp)%2==1?cnta+=mx:cntb+=mx;
while(!t[mx])--mx;
}
}
for(int i=mx;i>=1;i--)
{
while(t[i])
{
(++stp)%2==1?cnta+=i:cntb+=i;
t[i]--;
}
}
cout<<cnta-cntb<<"\n";
}
return 0;
}
C Park
樹形 dp,我不會。
點選檢視程式碼
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
register char ch=getchar();register int x=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
const int N=1e5+5,V=105;
int n,v,ans,a[N],f[N][V][2],g[N][V][2];
vector<int>G[N];
void dfs(int x,int p){
f[x][0][1]=g[x][0][1]=-1e16;
int sum=0;
for(int i=0;i<G[x].size();i++){
int y=G[x][i];
if(y==p)continue;
dfs(y,x);
sum+=a[y];
}
g[x][1][1]=sum+a[p];
for(int i=0;i<G[x].size();i++){
int y=G[x][i];
if(y==p)continue;
int mxf=-1e16,mxg=-1e16;
for(int j=v;j>=0;j--){
mxf=max(mxf,max(f[x][v-j][0],f[x][v-j][1]+a[p]-a[y])),
mxg=max(mxg,max(g[x][v-j][0],g[x][v-j][1]));
ans=max(ans,mxg+max(f[y][j][0],f[y][j][1]));
ans=max(ans,mxf+max(g[y][j][0],g[y][j][1]));
}
for(int j=1;j<=v;j++){
f[x][j][0]=max(f[x][j][0],max(f[y][j][0],f[y][j][1])),
g[x][j][0]=max(g[x][j][0],max(g[y][j][0],g[y][j][1]));
f[x][j][1]=max(f[x][j][1],max(f[y][j-1][0],f[y][j-1][1])+sum),
g[x][j][1]=max(g[x][j][1],max(g[y][j-1][0],g[y][j-1][1])+sum-a[y]+a[p]);
}
}
}
signed main(){
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
n=read(),v=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1,u,v;i<n;i++){
u=read(),v=read();
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1,0);
cout<<ans;
}
D 路徑
變形金剛。
我只會 \(35\),\(O(n^2 \log n)\) 暴力和 \(k=1\) 的 dp。。。