zoukankan      html  css  js  c++  java
  • 【2018.10.29】教科书般的亵渎 / 寻宝游戏 / 乐谱分段

    题目

    WZJ的pdf题解

    T1

    看过数据,发现只要检查好恶心的暴力就完了。

    题意就是让你枚举一种攻击方案使所有人的血量的最小值为 $0space orspace 1$ 且连续(可以有人血量相同)。

    枚举一下目标血量序列的最小值是 $0$ 还是 $1$,再枚举一下最大值,然后 $dfs$ 判断是否存在合法情况即可。

    不过我数组开小了(正好开的 $7$),输入 $b[7]$ 的时候指针爆到了 $m$ 处,然后把输入值刷给 $m$ 了……调了半天。

     1 #include<bits/stdc++.h>
     2 #define N 8
     3 #define M 8
     4 using namespace std;
     5 inline int read(){
     6     int x=0; bool f=1; char c=getchar();
     7     for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
     8     for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
     9     if(f) return x;
    10     return 0-x;
    11 }
    12 int n,m,a1[N],a2[N],b1[M],b2[M];
    13 int i,j;
    14 short vis[13];
    15 bool dfs(int cur,int cnt,int num){
    16     if(cur>m){
    17         if(cnt==j-i+1 && num==n+m) return 1;
    18         else return 0;
    19     }
    20     if(!a2[cur]){
    21         if(dfs(cur+1,cnt,num)) return 1;
    22         else return 0;
    23     }
    24     int hp,tmpcnt=cnt,tmpnum=num,tmp2,tmp1;
    25     for(int x=1;x<=n;++x){
    26         if(!b1[x]) continue;
    27         
    28         tmp1=max(b1[x]-a2[cur],0);
    29         if(tmp1<i) continue;
    30         if(--vis[b1[x]]==0 && b1[x]<=j) --cnt;
    31         swap(b1[x],tmp1);
    32         if(vis[b1[x]]++==0 && b1[x]<=j) ++cnt;
    33         if(tmp1>j && b1[x]<=j) ++num;
    34         
    35         tmp2=max(b2[cur]-a1[x],0);
    36         if(tmp2<i) continue;
    37         if(--vis[b2[cur]]==0 && b2[cur]<=j) --cnt;
    38         swap(b2[cur],tmp2);
    39         if(vis[b2[cur]]++==0 && b2[cur]<=j) ++cnt;
    40         if(tmp2>j && b2[cur]<=j) ++num;
    41         
    42         //printf("dfs:%d->%d %d %d  %d->%d %d->%d
    ",cur,x,cnt,num,tmp1,b1[x],tmp2,b2[cur]); 
    43         if(dfs(cur+1,cnt,num)) return 1;
    44         
    45         num=tmpnum;
    46         cnt=tmpcnt;
    47         --vis[b2[cur]];
    48         swap(b2[cur],tmp2);
    49         ++vis[b2[cur]];
    50         --vis[b1[x]];
    51         swap(b1[x],tmp1);
    52         ++vis[b1[x]];
    53     }
    54     if(dfs(cur+1,cnt,num)) return 1;
    55     return 0;
    56 }
    57 int main(){
    58     //freopen("defile.in","r",stdin);
    59     //freopen("defile.out","w",stdout);
    60     n=read(),m=read();
    61     int to=0;
    62     for(i=1;i<=n;++i) a1[i]=read(),b1[i]=read(),to=max(to,b1[i]),vis[b1[i]]++;
    63     for(i=1;i<=m;++i) a2[i]=read(),b2[i]=read(),to=max(to,b2[i]),vis[b2[i]]++;
    64     for(i=0;i<=1;++i){
    65         int lj=0,_lj=0;
    66         for(j=i;j<=min(i+n+m-1,to);++j){
    67             if(vis[j]) ++lj;//printf("%d %d %d %d %d
    ",i,j,lj,_lj+vis[j],vis[2]);
    68             if(dfs(1,lj,_lj+=vis[j])){printf("Yes
    "); return 0;}//system("pause");
    69         }
    70     }
    71     printf("No
    ");
    72     return 0;
    73 }
    74 /*
    75 4 3
    76 1 8 6 5 4 1 3 8
    77 4 2 7 2 8 6
    78 */
    View Code

    T2

    $noip2017space D2T2$ 再现

    什么,这状压裸题还用讲嘛?

    一看 $k=15$,以每个宝藏点为起点 $bfs$ 求一下它到其它各个宝藏点的最短距离,然后设 $dp(s,i)$ 表示宝藏点挖掘情况的 $01$ 集合为 $s$,当前最后挖到第 $i$ 个宝藏点时所需的最短时间。若一个情况被转移后总用时$le T$ ,就再更新一下能在规定时间 $T$ 内挖到的最大宝藏数量。这个计算嘛,我用的就是 $noip2018$ 提高组初赛 $T10$ 的做法,直接计算挖掘情况 $s$ 中 $1$ 的数量,就是挖的宝藏数量。

    时间复杂度 $O(2^k*k^2)$。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 inline int read(){
     4     int x=0; bool f=1; char c=getchar();
     5     for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
     6     for(; isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
     7     if(f) return x;
     8     return 0-x;
     9 }
    10 
    11 const int fx[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
    12 int n,m,k,T,dis[502][502],dp[1<<16][16],far[16][16];
    13 char c[502][502];
    14 vector<pair<int,int> >v;
    15 bool vis[502][502];
    16 void bfs(int s){
    17     queue<pair<int,int> >Q;
    18     Q.push(v[s]);
    19     memset(dis,0x7f,sizeof dis);
    20     memset(vis,0,sizeof vis);
    21     dis[v[s].first][v[s].second]=0;
    22     vis[v[s].first][v[s].second]=1;
    23     int i,x,y,gx,gy;
    24     while(!Q.empty()){
    25         x=Q.front().first, y=Q.front().second, Q.pop();
    26         for(i=0;i^4;++i){
    27             gx=x+fx[i][0], gy=y+fx[i][1];
    28             if(gx<1 || gy<1 || gx>n || gy>m || c[gx][gy]=='#' || vis[gx][gy]) continue;
    29             dis[gx][gy]=dis[x][y]+1, vis[gx][gy]=1;
    30             Q.push(make_pair(gx,gy));
    31         }
    32     }
    33 }
    34 
    35 int ans;
    36 int main(){
    37     //freopen("treasure.in","r",stdin);
    38     //freopen("treasure.out","w",stdout);
    39     n=read(),m=read(),k=read(),T=read();
    40     int i,j,p;
    41     v.push_back(make_pair(0,0));
    42     for(i=1;i<=n;++i){
    43         scanf("%s",c[i]+1);
    44         for(j=1;j<=m;++j){
    45             if(c[i][j]=='*') v.push_back(make_pair(i,j));
    46             if(c[i][j]=='S') v[0]=make_pair(i,j);
    47         }
    48     }
    49     for(i=0;i<=k;++i){
    50         bfs(i);
    51         for(j=1;j<=k;++j) far[i][j]=dis[v[j].first][v[j].second];
    52     }
    53     int to=1<<k,go;
    54     memset(dp,0x7f,sizeof dp);
    55     for(i=1,go=1; i<=k; ++i, go<<=1){
    56         dp[go][i]=far[0][i];
    57         if(dp[go][i]<=T) ans=1;
    58     }
    59     for(i=1;i^to;++i){
    60         for(j=1;j<=k;++j){
    61             if(!(i & (1<<(j-1)))){
    62                 go=i|(1<<(j-1));
    63                 for(p=1;p<=k;++p) if(i & (1<<(p-1))) dp[go][j]=min(dp[go][j],dp[i][p]+far[j][p]);
    64                     //printf("(%d,%d)<-(%d,%d) %d %d %d
    ",go,j,i,p,dp[go][j],dp[i][p],far[j][p]);
    65                 if(dp[go][j]<=T){
    66                     int tmp=go,zero=0;
    67                     while(tmp) tmp&=(tmp-1), ++zero;
    68                     ans=max(ans,zero);
    69                     //printf("newans:%d %d
    ",go,zero);
    70                 }
    71             }
    72         }
    73         //system("pause");
    74     }
    75     /*
    76     for(i=0;i^to;++i){
    77         for(j=1;j<=k;++j)
    78             if(!(i & (1<<(j-1)))) printf("%d ",dp[i|(1<<(j-1))][j]);
    79         putchar('
    ');
    80     }*/
    81     printf("%d
    ",ans);
    82     return 0;
    83 }
    84 /*
    85 4 5 6 9
    86 **...
    87 *##*.
    88 #**..
    89 ..S..
    90 */
    View Code

    T3

    神仙省选级题目,我感觉我要被集训队吊着打……

    20pts:

    瞎 jb 搜。

    60pts:

    设 $f_i$ 表示前 $i$ 个音符已经划分完毕,已经划分过的最短乐章最长是多少。

    易得 $f_i = max{min(f_j, i − j)}$,条件是 $[j + 1, i]$ 区间没有相同的音符。

    计算方案的话可以设 $g_i$ 表示前 $i$ 个音符已经划分完毕,已经划分过的乐章长度均 $ge f_n$ ,可得 $g_i =sum_{j=0}^{i−f_n} g_j$,其中 $[j + 1, i]$ 区间没有相同的音符,条件是 $j$ 为最大的满足要求的。

    至于求没有相同音符的区间 $[j + 1, i]$ ,一直向前扩展到出现一个重复字符为止就可以了,中间的 $j$ 都满足要求。

    答案即为 $f_n$ 和 $g_n$ ,时间复杂度为 $O(n^2)$。

    100pts:

    仔细思考,会想到求没有相同音符的区间 $[j + 1, i]$ 这个东西,可以用滑动窗口直接求最大的需要转移的 $j$,因为 $i$ 往右移动,$j$ 也会往右移动或不动。

    而快速取到最大 $j$ 的方法搞定后,$g$ 数组就只是简单地转移了前缀和。也就是说可以 $O(n)$ 推 $g$ 数组。

    但是 $f$ 数组的递推没法优化到 $O(n^2)$ 以下,因此不能再推它了。

    现在的问题成了如何直接得知 乐章长度下限 $f_n$。

    我们注意到可以通过二分卡下界($mid$ 设为最短乐章长度的最小值)的方式来求出 $f_n$。

    具体原因是,由于这种二分只卡下界,$f_n$ 具有单调性。如果 $f_n$ 取某一值可以,那取更大的值也可以。

    于是 $g_i=sum_{j=0}^{i-mid} g_j$。

    判断是否存在让每段乐章长度均$ge mid$ 的方案,直接判 $g_n$ 是否大于 $0$ 即可。

    时间复杂度 $O(n*log(n))$。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cctype>
     4 #include<cmath>
     5 #include<algorithm>
     6 #define rep(i,s,t) for(int i=s;i<=t;i++)
     7 #define dwn(i,s,t) for(int i=s;i>=t;i--)
     8 using namespace std;
     9 inline int read() {
    10     int x=0,f=1;char c=getchar();
    11     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    12     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    13     return x*f;
    14 }
    15 typedef long long ll;
    16 const int maxn=530010;
    17 const int mod=998244353;
    18 int n,A[maxn],f[maxn],st[maxn],last[maxn],tmp[maxn],g[maxn],sumv[maxn];
    19 int check(int lim) {
    20     sumv[0]=1;
    21     rep(i,1,n) {
    22         int l=st[i]-1,r=i-lim;
    23         if(l>r) f[i]=0;
    24         else f[i]=(sumv[r]-(l>=1?sumv[l-1]:0))?1:0;
    25         sumv[i]=sumv[i-1]+f[i];
    26     }
    27     return f[n];
    28 }
    29 int calc(int ans) {
    30     g[0]=sumv[0]=1;
    31     rep(i,1,n) {
    32         int l=st[i]-1,r=i-ans;
    33         if(l>r) g[i]=0;
    34         else g[i]=(sumv[r]-(l>=1?sumv[l-1]:0)+mod)%mod;
    35         sumv[i]=(sumv[i-1]+g[i])%mod;
    36     }
    37     return g[n];
    38 }
    39 int main() {
    40     //freopen("instrument.in","r",stdin);
    41     //freopen("instrument.out","w",stdout);
    42     n=read();
    43     rep(i,1,n) tmp[i]=A[i]=read();
    44     sort(tmp+1,tmp+n+1);
    45     rep(i,1,n) A[i]=lower_bound(tmp+1,tmp+n+1,A[i])-tmp;
    46     rep(i,1,n) st[i]=max(st[i-1],last[A[i]]+1),last[A[i]]=i;
    47     int l=1,r=n+1,mid;
    48     while(l+1<r) if(check(mid=l+r>>1)) l=mid; else r=mid;
    49     printf("%d
    %d
    ",l,calc(l));
    50     return 0;
    51 }
    View Code
  • 相关阅读:
    未来的计划和考虑
    jquery 常用的方法
    对于页面动态加载的元素事件无效的解决方案
    Myeclipse8.5中svn插件安装方法总结
    JS读RSS
    JAVA的RSS处理
    环境:win7+ie8 IE8的F12不起作用,原因如下:
    关闭和释放JDBC
    关于Eclipse无法生成class文件的问题
    JavaScript跨域总结与解决办法
  • 原文地址:https://www.cnblogs.com/scx2015noip-as-php/p/2018_10_29.html
Copyright © 2011-2022 走看看