CSP-S 模擬53 題解

題解:

T1 u:c++

一看到修改這麼多,但詢問其實只有一個不難想到差分,可是他這個形狀能夠說很不規則,因而咱們想到分別維護豎着的和斜着的差分,而後最後合併便可。ide

考場上瞎調了一波係數莫名AC,實際上是維護差分的差分。ui

考試時發現對拍暴力輸不出來東西時,慌的不行,對拍的數據範圍必定要搞對。spa

 1 //weihu xiezhede chafen?
 2 //對於每一個知足 x ∈ [r, r +l), y ∈ [c, x−r +c]
 3 //的元素 (x, y),將權值增長 s。
 4 #include<bits/stdc++.h>
 5 using namespace std;
 6 #define int long long
 7 #define sc(x) printf("%lld\n",x)
 8 const int N=1e3+10;
 9 int cf[N][N],cf1[N][N],n,q,a[N][N];
10 signed main(){
11     //freopen("data.in","r",stdin);
12     //freopen("my.out","w",stdout);
13     scanf("%lld%lld",&n,&q);
14     if(!q){puts("0");return 0;}
15     for(int i=1;i<=q;++i){
16         int r,c,l,s;
17         scanf("%lld%lld%lld%lld",&r,&c,&l,&s);
18         cf[r][c]+=s;
19         cf1[r][c+1]+=s;
20         if(r+l<=n) cf[r+l][c]-=s;
21         if(r+l<=n&&c+l+1<=n) cf1[r+l][c+l+1]-=s;
22     }
23     for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) cf[i][j]+=cf[i-1][j];
24     for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) cf1[i][j]+=cf1[i-1][j-1];
25     int ans=0;
26     for(int i=1;i<=n;++i){
27         for(int j=1;j<=n;++j){
28             cf[i][j]-=cf1[i][j];
29         }
30     }
31 //    ans=cf[1][1];
32     for(int i=1;i<=n;++i){
33         for(int j=1;j<=n;++j){
34             cf[i][j]+=cf[i][j-1];
35             //cout<<cf[i][j]<<" ";
36             ans^=cf[i][j];
37         }
38         //cout<<endl;
39     }
40     sc(ans);
41 }
u

 

T2 v:code

考場上想狀壓,可是發現數據範圍稍大,可能過不了,而後也沒什麼思路。blog

正解 記憶化搜索+hash_map,實際上是和裸狀壓同樣的,可是加了記憶化加速,比較難搞的一點就是如何把刪了一個球后的狀態用二進制表示出來,有點繞。ci

還有就是,hash_map不能僅僅記錄狀態,還要記錄當前所剩的球數,由於000110和000110對於狀態來講是同樣的,可是前面的黑球數是不必定的,這樣保證狀態惟一。因此hash_map有點難搞,%%%DeepinC重載中括號取地址hash_map,由於本身是實在是不會hash_map,因此就沒臉得照着DeepinC神的hash_map打了。hash

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=35;
 4 #define signed long long
 5 const int M=3e7+10;
 6 char s[N];
 7 int n,k,a[N];
 8 struct hash_map{//hash_map shizhaozhe DeepinC dedade zhendebuhui hash_map
 9     int first[30000017],nex[M],to[M],tot;short l[M],len;
10     double val[M];
11     double &operator[] (const register int st){
12         signed f=st*1ll*len%30000017;
13         for(register int i=first[f];i;i=nex[i]) if(to[i]==st&&l[i]==len) return val[i];
14         to[++tot]=st,nex[tot]=first[f],first[f]=tot,l[tot]=len; val[tot]=-1;return val[tot];
15     }
16 }mp;
17 inline double max(const register double  a,const register double b){
18     return a>b?a:b;
19 }
20 
21 double dfs(const register int l,const register int st){//cout<<l<<" "<<st<<endl;
22     if(l==n-k) return 0.0;
23     mp.len=l;//meicichongxinfuzhi,yinwei zhuangtaihechangdushiduiyingde
24     if(mp[st]>-0.1) return mp[st];
25     mp[st]=0;
26     short sta[N],jk=l+1,kh=(l>>1)+1;
27     for(register int i=1;i^jk;++i) sta[i]=(st>>i-1)&1;
28 //    reverse(sta+1,sta+l+1);
29 //    for(int i=1;i<=l;++i) cout<<sta[i]<<" ";cout<<endl;
30 
31     for(register int  i=1;i^kh;++i){
32         short h=l-i+1;
33         int state1=st>>l-i+1<<l-i|st&(1<<l-i)-1,state2=st>>l-h+1<<l-h|st&(1<<l-h)-1;
34 //        cout<<st<<" "<<l<<" "<<i<<endl;
35 //        cout<<state1<<" "<<state2<<endl;
36         double ans1=dfs(l-1,state1)+sta[h],ans2=dfs(l-1,state2)+sta[i];
37         mp.len=l;mp[st]+=(2.0*max(ans1,ans2))/(1.0*l);
38     }
39     if(l&1){
40         int i=kh;
41         int state=st>>l-i+1<<l-i|st&(1<<l-i)-1;
42         double ans=dfs(l-1,state)+sta[i];
43         mp.len=l;mp[st]+=ans/(1.0*l);
44     }
45     return mp[st];
46 }
47 
48 int main(){
49     scanf("%d%d",&n,&k);
50     scanf("%s",s+1);
51     int st=0;
52     for(register signed i=1;i<=n;++i) a[i]=(s[i]=='W');
53     for(register signed i=1;i<=n;++i) st=st<<1|a[i];
54     printf("%.7lf",dfs(n,st));
55 }
v

T3:it

考場上覺得是個貪心,就和虎那題差很少,其實是個思路很是好的dpevent

首先貪心地考慮,每一個邊頂多被覆蓋一次,由於被覆蓋兩次以上徹底能夠從這條便斷開,那麼會使答案更優。

咱們設$dp[i][0/1]$表示以點i爲根的子樹否/是向上伸,由於他的兩個答案是同時更新的,因此。

而後考慮對於i的兒子y,咱們設兩個二元組w1,w2,w1表示向上伸,w2表示不向上伸。

那麼咱們考慮轉移$w1=min(w1+dp[y][0],w2+dp[y][1])$,$w2=min(w1+dp[y][1],w2+dp[y][0])$

那麼咱們在來考慮怎麼用w1,w2進行轉移。

若是他這條邊不翻轉,那麼能不反轉就不反轉,因此$dp[x][1]=(INF,INF)$,$dp[x][0]=min(w2,(w1.first+1,w1.second))$

若是必須反轉的話,那麼同理$dp[x][0]=(INF,INF)$,$dp[x][1]=min((w1.first,w1.second+1),(w2.first+1,w2.second+1))$

最後答案就是$dp[1][0].first/2$和$dp[1][0].second$

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=3e5+10,INF=1e9+10;
 4 int first[N],nex[N<<1],to[N<<1],edge[N<<1],tot;
 5 void add(int a,int b,int c){
 6     to[++tot]=b,nex[tot]=first[a],first[a]=tot,edge[tot]=c;
 7 }
 8 pair<int ,int> min(pair<int ,int> a,pair<int ,int > b){
 9     return a<b?a:b;
10 }
11 pair<int ,int> add(pair<int,int> a,pair<int ,int> b){
12     return make_pair(a.first+b.first,a.second+b.second);
13 }
14 pair<int ,int> dp[N][2];//0 not up 1 up
15 void dfs(int x,int fa,int ed){
16     pair<int ,int > p,q;
17     p=make_pair(INF,INF);//up
18     q=make_pair(0,0);//not up
19     pair<int ,int> tmp1,tmp2;//p q;
20     for(int i=first[x];i;i=nex[i]){
21         int y=to[i];
22         if(y==fa) continue;
23         dfs(y,x,edge[i]);
24         tmp1=min(add(p,dp[y][0]),add(q,dp[y][1]));
25         tmp2=min(add(q,dp[y][0]),add(p,dp[y][1]));
26         p=make_pair(tmp1.first,tmp1.second);
27         q=make_pair(tmp2.first,tmp2.second);
28     }
29     if(ed==1||ed==2){//bi fan
30         dp[x][1]=min(make_pair(p.first,p.second+1),make_pair(q.first+1,q.second+1));
31     }else dp[x][1]=make_pair(INF,INF);
32     if(ed==0||ed==2){//bu fan
33         dp[x][0]=min(q,make_pair(p.first+1,p.second));
34     }else dp[x][0]=make_pair(INF,INF);
35 }
36 
37 int main(){
38     int n;
39     scanf("%d",&n);
40     for(int i=1;i<n;++i){
41         int a,b,c,d;
42         scanf("%d%d%d%d",&a,&b,&c,&d);
43         int opt;
44         if(d==2) opt=2;
45         else if(c^d) opt=1;
46         else opt=0;
47         add(a,b,opt);
48         add(b,a,opt);
49     }
50     dfs(1,0,2);
51     printf("%d %d",dp[1][0].first>>1,dp[1][0].second);
52 }
View Code
相關文章
相關標籤/搜索