题解:
T1 u:
一看到修改这么多,但询问其实只有一个不难想到差分,但是他这个形状可以说很不规则,于是我们想到分别维护竖着的和斜着的差分,然后最后合并即可。
考场上瞎调了一波系数莫名AC,其实是维护差分的差分。
考试时发现对拍暴力输不出来东西时,慌的不行,对拍的数据范围一定要搞对。
1 //weihu xiezhede chafen? 2 //对于每个满足 x ∈ [r, r +l), y ∈ [c, x−r +c] 3 //的元素 (x, y),将权值增加 s。 4 #include5 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< 36 ans^=cf[i][j]; 37 } 38 //cout< 39 } 40 sc(ans); 41 }
T2 v:
考场上想状压,但是发现数据范围稍大,可能过不了,然后也没什么思路。
正解 记忆化搜索+hash_map,其实是和裸状压一样的,但是加了记忆化加速,比较难搞的一点就是如何把删了一个球后的状态用二进制表示出来,有点绕。
还有就是,hash_map不能仅仅记录状态,还要记录当前所剩的球数,因为000110和000110对于状态来说是一样的,但是前面的黑球数是不一定的,这样保证状态唯一。所以hash_map有点难搞,%%%DeepinC重载中括号取地址hash_map,因为自己是实在是不会hash_map,所以就没脸得照着DeepinC神的hash_map打了。
1 #include2 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< 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< ,state2=st>>l-h+1<30 31 for(register int i=1;i^kh;++i){ 32 short h=l-i+1; 33 int state1=st>>l-i+1< <1 1 1< 1; 34 // cout< 35 // cout< ; 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 }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< <1 1
T3:
考场上以为是个贪心,就和虎那题差不多,实际上是个思路非常好的dp
首先贪心地考虑,每个边顶多被覆盖一次,因为被覆盖两次以上完全可以从这条便断开,那么会使答案更优。
我们设$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 #include2 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 aa: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 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 }