日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

NOIP模拟测试17「入阵曲·将军令·星空」

發布時間:2023/12/2 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 NOIP模拟测试17「入阵曲·将军令·星空」 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

入陣曲

題解

應用了一種美妙移項思想,

我們先考慮在一維上的做法

維護前綴和$(sum[r]-sum[l-1])\%k==0$可以轉化為

$sum[r]\% k==sum[l-1]\%k$開個桶維護一下即可

然后拓展到二維上

把兩行之間所有行拍扁看作一維上的區間,

我們枚舉兩行和行之間所有列開個桶維護

$n^2 m$復雜度

for(ll i=1;i<=n;i++)for(ll j=1;j<=i;j++){flag[0]=1;for(ll q=1;q<=m;q++){t[q]=(sum[i][q]-sum[j-1][q]+k)%k;cnt+=flag[t[q]];flag[t[q]]++;}for(ll q=1;q<=m;q++)flag[t[q]]=0;}

至于桶里flag[0]=1初始化含義

當你其他%==0的矩陣放進去時本身就符合條件,在桶里找配對之前就構成合法矩陣,這樣做統計了所有%=0的情況

當然這樣也行

for(ll i=1;i<=n;i++)for(ll j=1;j<=i;j++){for(ll q=1;q<=m;q++){t[q]=(sum[i][q]-sum[j-1][q]+k)%k;cnt+=flag[t[q]];flag[t[q]]++;}cnt+=flag[0];for(ll q=1;q<=m;q++)flag[t[q]]=0;}

將軍令

題解

$45\%$算法

計算k==1

和小胖收皇宮類似,

思考dp數組含義

$f[x][0]$表示被父親管轄?? $f[x][1]$表示被自己管轄?? $f[x][2]$表示被自己兒子管轄

f數組轉移

若x被父親管轄,那么兒子必須被自己管轄或者被兒子的兒子管轄

$f[x][0]=\sum\limits_{y}^{y\in son}min(f[y][1],f[y][2])$

若x被自己管轄,那么x轉移隨意

$f[x][1]=\sum\limits_{y}^{y\in son} min(f[y][1],f[y][2],f[y][0])$

若x被兒子管轄,那么兒子可以被自己管轄或者被兒子的兒子管轄

但如果所有兒子的兒子代價都比選自己代價小,我們需要強制選出一個$f[y][1]-f[y][2]$差值最小的更新

代碼稍微體會一下

void dp(ll x){if(!son[x]) {f[x][1]=1;f[x][2]=0x7ffffff;f[x][0]=0;return ;}vis[x]=1;ll sum=0,sum2=0,sum3=0,pan=0,mix=0x7ffffff;for(ll i=head[x];i;i=nxt[i]){ll y=ver[i];if(vis[y]) continue;dp(y);sum+=min(f[y][0],min(f[y][1],f[y][2]));sum2+=min(f[y][2],f[y][1]);sum3+=min(f[y][1],f[y][2]);if(f[y][1]<=f[y][2]) pan=1;else mix=min(mix,f[y][1]-f[y][2]);}f[x][1]=sum+1;f[x][0]=sum2;if(pan==1) f[x][2]=sum3;else f[x][2]=sum3+mix; }

$75\%$算法

計算k==2

還是思考dp數組含義

如果還是像上一個那樣定義要寫死

換一種0表示被自己守,1表示被兒子守(至少選了一個兒子),2被孫子守(至少選了一個孫子),3子孫全被覆蓋自己沒有,4孫子全被覆蓋(兒子可以被覆蓋可以不被覆蓋)自己沒有

還是思考轉移

被自己守x轉移還是隨意$f[x][0]=\sum\limits_{y}^{y\in son} min(f[y][0],f[y][1],f[y][2],f[y][3],f[y][4])$

被兒子守x轉移比較復雜

兒子需要自保,因為兒子可以管轄自己兄弟,所以隨意選,所以可以選到$f[y][3]$

$f[x][1]=\sum\limits_{y}^{y\in son} min(f[y][0],f[y][1],f[y][2],f[y][3])$

也和k==1類似,顯然我們還是要選出來一個最小差值

被自己孫子守,那么自己兒子需要自保,$f[y][1],f[y][2],f[y][0]$都滿足條件

子孫全被覆蓋自己沒有,那么就是兒子孫子全被覆蓋,兒子本身也要被覆蓋,

$f[y][0]$? $f[y][1]$?? $f[y][2]$????????? (顯然$f[y][3]$不行)

孫子全被覆蓋,那么就是孫子全被覆蓋,那么可以是$f[y][3]$,$f[y][1]$,$f[y][0]$,$f[y][2]$

代碼稍微體會一下(這個代碼有誤,我并不能調出來,神奇的是我優化調出來了)

void dp2(ll x){ //1表示被自己守,2表示被兒子,3被孫子,4子孫全有自己無,5孫子全有自己無if(!son[x]){f2[x][4]=0x7fffffff;f2[x][5]=0x7fffffff;f2[x][1]=1;f2[x][2]=0;f2[x][3]=0;return ;}vis[x]=1;ll sum1=0,sum2=0,sum3=0,sum4=0,sum5=0,pan=0,mix1=0x7fffffff,pan2=0,mix2=0x7ffffff;for(ll i=head[x];i;i=nxt[i]){ll y=ver[i];if(vis[y]) continue;dp2(y);sum1+=min(min(f2[y][1],f2[y][2]),min(f2[y][3],min(f2[y][4],f2[y][5])));sum2+=min(min(f2[y][1],f2[y][2]),min(f2[y][3],f2[y][4]));if(f2[y][1]<=f2[y][2]&&f2[y][1]<=f2[y][3]&&f2[y][1]<=f2[y][4])pan=1;elsemix1=min(mix1,f2[y][1]-min(f2[y][2],min(f2[y][3],f2[y][4])));sum3+=min(f[y][1],min(f[y][2],f[y][3]));if(f2[y][2]<=f2[y][1]&&f2[y][2]<=f2[y][3])pan2=1;elsemix2=min(mix2,f2[y][2]-min(f2[y][1],f2[y][3]));sum4+=min(min(f2[y][1],f2[y][2]),f2[y][3]);sum5+=min(min(f2[y][1],f2[y][2]),min(f2[y][3],f2[y][4]));}f2[x][1]=1+sum1;if(pan==1)f2[x][2]=sum2;else f2[x][2]=sum2+mix1;if(pan2==1)f2[x][3]=sum3;else f2[x][3]=sum3+mix2;f2[x][4]=sum4;f2[x][5]=sum5; }

思考怎么優化

dp數組含義再次轉變

$f[x][w]$表示$f$中<=w最小的數

例如$f[x][4]$表示$min(f[x][1],f[x][2],f[x][3],f[x][4],f[x][0])$

轉移類似

$f[x][0]=\sum\limits_{y}^{y\in son} f[y][4]? $$ +1$

$f[x][3]=\sum\limits_{y}^{y\in son} f[y][2]? $

$f[x][2]=\sum\limits_{y}^{y\in son} f[y][3]? $$+差值$

$f[x][4]=\sum\limits_{y}^{y\in son} f[y][3]? $

$f[x][1]=\sum\limits_{y}^{y\in son} f[x][4]? $$+差值$

最后1 2 3 4 互相取min具體看代碼

再次感受一下

void dp2(ll x){if(!son[x]){f2[x][0]=1;f2[x][1]=f2[x][2]=1;f2[x][3]=f2[x][4]=0;f2[x][1]=0x7fffffff;return ;}vis[x]=1;f2[x][0]=1;f2[x][1]=f2[x][2]=f2[x][3]=f2[x][4]=0;ll pan=0,mix1=0x7fffffff,pan2=0,mix2=0x7ffffff;for(ll i=head[x];i;i=nxt[i]){ll y=ver[i];if(vis[y]) continue;dp2(y);f2[x][0]+=f2[y][4];f2[x][3]+=f2[y][2];f2[x][4]+=f2[y][3];mix1=min(f2[y][0]-f2[y][3],mix1);mix2=min(f2[y][1]-f2[y][2],mix2);}f2[x][1]=f2[x][4]+mix1;f2[x][2]=min(f2[x][3]+mix2,min(f2[x][0],f2[x][1]));f2[x][3]=min(f2[x][3],f2[x][2]);f2[x][4]=min(f2[x][3],f2[x][4]); // printf("mix1=%lld 2=%lld x=%lld f[][1]=%lld [2]=%lld [3]=%lld [4]=%lld [0]=%lld\n",mix1,mix2,x,f2[x][1],f2[x][2],f2[x][3],f2[x][4],f2[x][0]); }

?$100\%$算法

dp我是打不出來

應該會有別的大神打出來dp100分

那么正解是什么神奇的算法呢?

簡單貪心!

?

啊啊啊啊啊又是貪心,我又沒有看出來它是貪心,awsl,我太菜了

步驟分比正解難的多得多

貪心10分鐘改完AC,每次找到最深得節點找它的k級父親

實現不要想復雜,暴力改,暴力跳即可

你會發現你比dp還要快!!!!!!!!!!!!!!!!!!!

#include<bits/stdc++.h> using namespace std; #define ll long long #define A 1010101 ll n,k,t,tot=0,sum1=0,sum2=0,sumji=0,sumou=0,skriller=0; ll head[A],nxt[A],ver[A],deep[A],son[A],f[A][3],fa[A]; ll f2[A][10]; struct node{ll deep,x;friend bool operator < (node a,node b){return a.deep<b.deep;} }point[A]; priority_queue<node> q; bool vis[A]; void add(ll x,ll y){nxt[++tot]=head[x];head[x]=tot;ver[tot]=y; } ll read(){ll f=1,x=0;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return f*x; } void dfs(ll x,ll de){vis[x]=1;point[x].deep=de;point[x].x=x;q.push(point[x]);for(ll i=head[x];i;i=nxt[i]){ll y=ver[i];if(vis[y]) continue;dfs(y,de+1);son[x]++;fa[y]=x;} } void dp(ll x){if(!son[x]) {f[x][1]=1;f[x][2]=0x7ffffff;f[x][0]=0;return ;}vis[x]=1;ll sum=0,sum2=0,sum3=0,pan=0,mix=0x7ffffff;for(ll i=head[x];i;i=nxt[i]){ll y=ver[i];if(vis[y]) continue;dp(y);sum+=min(f[y][0],min(f[y][1],f[y][2]));sum2+=min(f[y][2],f[y][1]);sum3+=min(f[y][1],f[y][2]);if(f[y][1]<=f[y][2]) pan=1;else mix=min(mix,f[y][1]-f[y][2]);}f[x][1]=sum+1;f[x][0]=sum2;if(pan==1) f[x][2]=sum3;else f[x][2]=sum3+mix; } ll find(ll x){ll w=1;while(w<=k){w++;x=fa[x];}return x; } void dp2(ll x){if(!son[x]){f2[x][0]=1;f2[x][1]=f2[x][2]=1;f2[x][3]=f2[x][4]=0;f2[x][1]=0x7fffffff;return ;}vis[x]=1;f2[x][0]=1;f2[x][1]=f2[x][2]=f2[x][3]=f2[x][4]=0;ll pan=0,mix1=0x7fffffff,pan2=0,mix2=0x7ffffff;for(ll i=head[x];i;i=nxt[i]){ll y=ver[i];if(vis[y]) continue;dp2(y);f2[x][0]+=f2[y][4];f2[x][3]+=f2[y][2];f2[x][4]+=f2[y][3];mix1=min(f2[y][0]-f2[y][3],mix1);mix2=min(f2[y][1]-f2[y][2],mix2);}f2[x][1]=f2[x][4]+mix1;f2[x][2]=min(f2[x][3]+mix2,min(f2[x][0],f2[x][1]));f2[x][3]=min(f2[x][3],f2[x][2]);f2[x][4]=min(f2[x][3],f2[x][4]); // printf("mix1=%lld 2=%lld x=%lld f[][1]=%lld [2]=%lld [3]=%lld [4]=%lld [0]=%lld\n",mix1,mix2,x,f2[x][1],f2[x][2],f2[x][3],f2[x][4],f2[x][0]); } void dfs2(ll x,ll fa,ll de){vis[x]=1;if(de==k) return ;for(ll i=head[x];i;i=nxt[i]){ll y=ver[i];if(y==fa) continue;dfs2(y,x,de+1);} } int main(){n=read(),k=read(),t=read(); // printf("%lld\n",k);if(k==0){for(ll i=1,a,b;i<=n-1;i++){a=read(),b=read();}printf("%lld\n",n);return 0;} /* if(k==1){for(ll i=1,a,b;i<=n-1;i++){a=read(),b=read();add(a,b);add(b,a);}dfs(1,1);memset(vis,0,sizeof(vis));dp(1);printf("%lld\n",min(f[1][1],f[1][0]));return 0;} */ if(k==2){memset(f2,0x3f,sizeof(f2));for(ll i=1,a,b;i<=n-1;i++){a=read(),b=read();add(a,b);add(b,a);}dfs(1,1);memset(vis,0,sizeof(vis));dp2(1);printf("%lld\n",f2[1][2]);return 0;}else{for(ll i=1,a,b;i<=n-1;i++){a=read(),b=read();add(a,b);add(b,a);}dfs(1,1);memset(vis,0,sizeof(vis));while(!q.empty()){ll x=q.top().x;q.pop();if(vis[x]) continue;ll f=find(x); // printf("x=%lld f=%lld\n",x,f);dfs2(f,0,0);skriller++;}printf("%lld\n",skriller);} }

星空

題解

首先如果翻轉我們楞翻轉一次復雜度最高n那么考慮優化

我們將取反轉化為異或

思考$1 xor 1=0$

$0 xor 1=1$

那么取反我們就轉化為了$xor 1$

定義差分數組為$b[i]=a[i] xor a[i+1]$

整段區間$xor1$差分(第一次看到異或的差分),我們轉化為$l xor1$ $r+1xor1$

我們不可能白白翻轉一段全是$1$的

我們翻轉至少有$1$個零

翻轉兩端都有$0$那么就可以看作消去

兩端只有一端有$0$那么可以看作移動

那么問題就轉化為了如何最少移動消去使所有$0$變為$1$

處理出任意兩個點之間消去代價(可以完全背包,把每個操作換成$+ $,$-$ 兩個代價)

for(ll i=1;i<=m;i++)for(ll j=a[i];j<=n;j++)d[j]=min(d[j-a[i]]+1,d[j]);for(ll i=1;i<=m;i++)for(ll j=n-a[i];j;j--)d[j]=min(d[j+a[i]]+1,d[j]);

考慮k很小,然后狀壓解決把所有點消去代價

memset(f,0x7f,sizeof(f));f[0]=0;for(ll i=0;i<ci[cnt];i++){for(ll j=0;j<cnt;j++){if(!(ci[j]&i)){for(ll k=j+1;k<cnt;k++){if((!(ci[k]&i))){if(f[i]>100000000) continue;else { // printf(" i=%lld j=%lld k=%lld cij=%lld cik=%lld f=%lld\n",i,j,k,ci[j],ci[k],f[i]);f[i|ci[j]|ci[k]]=min(f[i|ci[j]|ci[k]],f[i]+d[abs(pos[j]-pos[k])]); // printf("f=%lld d=%lld\n",f[i],d[abs(pos[j]-pos[k])]); }}}break;}}}

代碼

#include<bits/stdc++.h> using namespace std; #define ll long long #define A 111111 ll b[A],d[A],Xor[A],pos[A],ci[A],f[A],a[A]; ll cnt,m,n,k; inline void init() {memset(d,0x3f,sizeof(d));d[0]=0;for(ll i=1;i<=m;i++)for(ll j=a[i];j<=n;j++)d[j]=min(d[j-a[i]]+1,d[j]);for(ll i=1;i<=m;i++)for(ll j=n-a[i];j;j--)d[j]=min(d[j+a[i]]+1,d[j]);for(ll i=1;i<=n;i++){if(Xor[i])pos[cnt++]=i;} /* for(ll i=1;i<=n;i++){printf("%lld\n",d[i]);}printf("cnt=%lld\n",cnt); */} inline void dp(){memset(f,0x7f,sizeof(f));f[0]=0;for(ll i=0;i<ci[cnt];i++){for(ll j=0;j<cnt;j++){if(!(ci[j]&i)){for(ll k=j+1;k<cnt;k++){if((!(ci[k]&i))){if(f[i]>100000000) continue;else { // printf(" i=%lld j=%lld k=%lld cij=%lld cik=%lld f=%lld\n",i,j,k,ci[j],ci[k],f[i]);f[i|ci[j]|ci[k]]=min(f[i|ci[j]|ci[k]],f[i]+d[abs(pos[j]-pos[k])]); // printf("f=%lld d=%lld\n",f[i],d[abs(pos[j]-pos[k])]); }}}break;}}} } int main(){ci[0]=1;for(ll i=1;i<=30;i++)ci[i]=ci[i-1]<<1/*,printf("ci[%lld]=%lld\n",i,ci[i])*/;scanf("%lld%lld%lld",&n,&k,&m);n++;for(ll i=1,ak;i<=k;i++){scanf("%lld",&ak);b[ak]^=1;}for(ll i=1;i<=n;i++){Xor[i]=b[i-1]^b[i];}for(ll i=1;i<=m;i++){scanf("%lld",&a[i]);}init();dp();printf("%lld\n",f[ci[cnt]-1]); }

?

轉載于:https://www.cnblogs.com/znsbc-13/p/11336022.html

總結

以上是生活随笔為你收集整理的NOIP模拟测试17「入阵曲·将军令·星空」的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。