• NOIP模拟赛-2018.10.22


    模拟赛

      今天第一节课是历史,当然是不可能上的,一来到机房发现今天高二考试...

      老师说以后可能还要给高一考...那还不如现在跟着做好了,毕竟在学长学姐中垫底显得没那么丢人

      这套题风格挺奇怪的...为什么前面还是神牛后面直接成牛了...

      T1:http://hzwer.com/5053.html

      题意概述:给出一个长度为$n$的数列,从某个地方把它分成两部分(均不为空),从前半部分选出一些数,后半部分选出一些数,使得前面这些数的$xor$和等于后面的$and$和,求方案数. $n<=10^3,0<=a_i<1024$

      差点被题意杀,其实这个分割点只是限制前后分组顺序的,分割点不同但前后选的人均相同时视为不同的方案.选的人都相同但是分组不同,如$([2,2,3],[3]),([2],[2,2,3])$也算两种方案.

      明确了题意就好做多了.可以发现数据范围并不是很大,所以可以枚举断点求方案数.又发现数据范围真的不是很大,所以也可以枚举$xor$和.又发现...再枚举真要超时了.

      枚举了这些之后就只需要求出前$i$个中选出一些数使得$xor$和为$x$的方案数,后$i$个中选出一些数使得$and$和为$x$的方案数.这样就比较简单啦!随便$dp$转移一下就行.不过有可能会出现重复方案,对于这个问题固定第一个区间的右端点必选即可.

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <queue>
     4 # include <cstring>
     5 # include <string>
     6 # define R register int
     7 # define ll long long
     8 # define mod 1000000007
     9 
    10 using namespace std;
    11 
    12 const int maxn=1003;
    13 int n,m;
    14 int a[maxn],xorr[maxn][1030],andd[maxn][1030],ans;
    15 
    16 int main()
    17 {
    18     scanf("%d",&n);
    19     for (R i=1;i<=n;++i)
    20         scanf("%d",&a[i]),m=max(m,a[i]);
    21     for (R i=1;i<=n;++i)
    22     {
    23         xorr[i][ a[i] ]=1;
    24         for (R j=0;j<=m;++j)
    25             xorr[i][ a[i]^j ]=(xorr[i][ a[i]^j ]+xorr[i-1][j])%mod;
    26         for (R j=0;j<=m;++j)
    27             xorr[i][j]=(xorr[i][j]+xorr[i-1][j])%mod;
    28     }
    29     for (R i=n;i>=1;--i)
    30     {
    31         andd[i][ a[i] ]=1;
    32         for (R j=0;j<=m;++j)
    33             andd[i][ a[i]&j ]=(andd[i][ a[i]&j ]+andd[i+1][j])%mod;
    34         for (R j=0;j<=m;++j)
    35             andd[i][j]=(andd[i][j]+andd[i+1][j])%mod;
    36     }
    37     for (R i=1;i<n;++i)
    38         for (R j=0;j<=m;++j)
    39             ans=(1LL*(xorr[i][j]-xorr[i-1][j]+mod)*andd[i+1][j]%mod+ans)%mod;
    40     printf("%d",ans);
    41     fclose(stdin);
    42     fclose(stdout);
    43     return 0;
    44 }
    T1

     

      T2:http://hzwer.com/5042.html

      题意概述:一个长度为$n$的序列,每个数的取值是$0-L$,求有多少种取值方案使得可以从这些数中取出一些数,且和为$k$.$n,k<=20,L<=10^9$

      看起来挺像组合数学的,毕竟$l$非常大,好像只能用非常快的算法.首先用插板法算出把$k$个数分成$1->n$份的方案数,然后把这些数再组合数一番放进$n$个位置中,其他位置从$[1,L]$中任意取即可.听起来非常好,然而是不是有点太快了?如果真是这么做的话完全可以把$n,k$都放大一百倍,手玩一组发现这个做法会重复...而且我几乎不会容斥.

      突然想到某一个讲座的时候:"我就打了$6$个$dp$,就……",其实这道题的$dp$思路不是特别难想,一开始想的是$dp[i][j]$表示前$i$个数,拼出来的数最大是$j$的方案数,这种方程特别好转移,然而一点实际意义也没有...所以能拼出来的数必须全表示出来,$dp[i][j]$表示前$i$个数,能拼出来的数的状态是$j$的方案数.转移的时候枚举上一位的状态以及这一位填什么即可.停!$L$不是$10^9$吗?其实我们只关心能不能拼出$k$,所以大于$k$的数对于状态是没有贡献的,这一部分直接乘起来就可以了.

      

      注意...虽然$l$的范围非常大,$k$的范围非常小,但是这并不能说明$l<k$,转移的时候不能直接转移到$k$,而是$min(k,l)$,因为这个丢了$20$分,伤心.

      对了,别忘了开滚动数组.

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <queue>
     4 # include <cstring>
     5 # include <string>
     6 # define R register int
     7 # define ll long long
     8 # define mod 1000000007
     9 
    10 using namespace std;
    11 
    12 const int maxn=2100000;
    13 int n,k,l,vis[50],viss[50],maxz;
    14 int dp[3][maxn];
    15 ll ans=0;
    16 
    17 int main()
    18 {
    19     scanf("%d%d%d",&n,&k,&l);
    20     maxz=(1<<(k+1))-1;
    21     dp[0][0]=1;
    22     for (R i=0;i<n;++i)
    23     {
    24         int las=i&1;
    25         int now=las^1;
    26         memset(dp[now],0,sizeof(dp[now]));
    27         for (R z=0;z<=maxz;++z)
    28         {
    29             if(i==1&&z==2) 
    30                 i=1;
    31             if(!dp[las][z]) continue;
    32             vis[0]=true;
    33             int t=z;
    34             for (R x=1;x<=k;++x)
    35                 vis[x]=t%2,t/=2;
    36             for (R x=0;x<=k;++x)
    37             {
    38                 if(x>l) break;
    39                 for (R j=0;j<=k;++j) viss[j]=vis[j];
    40                 for (R j=0;j<=k;++j) if(vis[j]) viss[j+x]=true;
    41                 int nexz=0;
    42                 for (R j=k;j>=1;--j) 
    43                     nexz=nexz*2+viss[j];
    44                 dp[now][nexz]=(dp[now][nexz]+dp[las][z])%mod;
    45             }
    46             if(l>k) dp[now][z]=(dp[now][z]+1LL*dp[las][z]*(l-k)%mod)%mod;
    47         }
    48     }
    49     for (R i=0;i<=maxz;++i)
    50         if(i&(1<<(k-1)))
    51             ans=(ans+dp[n&1][i])%mod;
    52     printf("%lld",ans);
    53     return 0;
    54 }
    T2

      T3:一个数据范围消失了的分层图最短路...因为没有数据范围于是直接选择性失明不管那个限制了,竟然水了$70$...事实上因为限制点的数量非常小,直接$dfs$即可.

      
      1 # include <cstdio>
      2 # include <iostream>
      3 # include <cstring>
      4 # include <queue>
      5 # include <string>
      6 # define inf 10000000
      7 # define R register int
      8 
      9 using namespace std;
     10 
     11 const int dx[]={-1,1,0,0};
     12 const int dy[]={0,0,-1,1};
     13 const int maxn=104;
     14 char st[105];
     15 int n,m,ans=-1,bx,by,ex,ey;
     16 int g[maxn][maxn],sx[10],sy[10],h;
     17 int vis[maxn][maxn][10];
     18 struct z
     19 {
     20     int val,x,y,k;
     21 };
     22 queue <z> q;
     23 
     24 bool mw (int x,int y,int k,int d)
     25 {
     26     int    xx=x+dx[d];
     27     int yy=y+dy[d];
     28     if(xx<=0||xx>n||yy<=0||yy>n) return false;
     29     if(g[xx][yy]==-1) return false;
     30     return true;
     31 }
     32 
     33 int dij (int ext)
     34 {
     35     memset(vis,-1,sizeof(vis));
     36     while (q.size()) q.pop();
     37     int x,y,k,xx,yy;
     38     z a,b;
     39     a.x=bx;
     40     a.y=by;
     41     a.val=0;
     42     a.k=0;
     43     q.push(a);
     44     vis[ a.x ][ a.y ][0]=0;
     45     while (q.size())
     46     {
     47         a=q.front();
     48         q.pop();
     49         x=a.x;
     50         y=a.y;
     51         k=a.k;
     52         for (R d=0;d<4;++d)
     53         {    
     54             if(!mw(x,y,k,d)) continue;
     55             xx=x+dx[d];
     56             yy=y+dy[d];
     57             b.x=xx;
     58             b.y=yy;
     59             if(g[xx][yy]==k+1) b.k=k+1;
     60             else b.k=k;
     61             b.val=a.val+1;
     62             if(vis[xx][yy][b.k]!=-1) continue;
     63             vis[xx][yy][b.k]=b.val;
     64             q.push(b); 
     65         }
     66     }
     67     if(vis[ex][ey][m]!=-1) return vis[ex][ey][m]+ext;
     68     return -1;
     69 }
     70 
     71 void dfs (int x,int ext)
     72 {
     73     if(x==h+1)
     74     {
     75         int t=dij(ext);
     76         if(ans==-1) ans=t;
     77         if(t!=-1) ans=min(ans,t);
     78     }
     79     else
     80     {
     81         g[ sx[x] ][ sy[x] ]=-1;
     82         dfs(x+1,ext);
     83         g[ sx[x] ][ sy[x] ]=0;
     84         dfs(x+1,ext+1);
     85     }
     86 }
     87 
     88 int main()
     89 {
     90     scanf("%d%d",&n,&m);
     91     memset(vis,1,sizeof(vis));
     92     for (R i=1;i<=n;++i)
     93     {
     94         scanf("%s",st+1);
     95         for (R j=1;j<=n;++j)
     96         {
     97             if(st[j]=='T') ex=i,ey=j;
     98             else if(st[j]=='K') bx=i,by=j;
     99             else if(st[j]=='#') g[i][j]=-1;
    100             else if(st[j]=='.') g[i][j]=0;
    101             else if(st[j]=='S') sx[++h]=i,sy[h]=j;
    102             else g[i][j]=st[j]-'0';
    103         }
    104     }
    105     dfs(1,0);
    106     if(ans!=-1) 
    107         printf("%d",ans);
    108     else
    109         printf("impossible");
    110     return 0;
    111 }
    T3

    ---shzr

  • 相关阅读:
    线程
    unix架构
    Unix命令
    可重入函数reentrant function
    Eclipse 中 program arguments 与 VM arguments 的区别
    Java中Generics的使用
    Java的Reflection机制
    Java按值传递、按引用传递
    Java label
    LeetCode Merge Intervals
  • 原文地址:https://www.cnblogs.com/shzr/p/9830919.html
Copyright © 2020-2023  润新知