zoukankan      html  css  js  c++  java
  • NOIP2017题解

    小凯的疑惑

    a*b-a-b

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<stack>
     8 #include<queue>
     9 #include<set>
    10 #include<vector>
    11 #include<map>
    12 #define LL long long
    13 using namespace std;
    14 int main(){
    15   LL a,b;
    16   scanf("%lld%lld",&a,&b);
    17   printf("%lld",a*b-(a+b));
    18   return 0;
    19 }
    小凯的疑惑

    时间复杂度

    有点麻烦的模拟,注意细节.(出题人XXX)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<stack>
     8 #include<queue>
     9 #include<set>
    10 #include<vector>
    11 #include<map>
    12 #define U unsigned
    13 using namespace std;
    14 struct data{
    15   char s[2],x[5],y[5];
    16 }fo[200];
    17 char o[10],fe[200][2];
    18 bool bj[30];
    19 int S[200];
    20 int main(){
    21   int T,n;
    22   scanf("%d",&T);
    23   while(T){T--;
    24     scanf("%d%s",&n,o);
    25     int sum=0;memset(bj,0,sizeof(bj));bool fl=1;
    26     for(int i=1;i<=n;i++){
    27       scanf("%s",fe[i]);
    28       if(fe[i][0]=='F'){
    29     scanf("%s%s%s",fo[i].s,fo[i].x,fo[i].y);
    30     int ch=fo[i].s[0]-'a';
    31     if(bj[ch]) fl=0;bj[ch]=1;
    32     S[++sum]=ch;
    33       }
    34       else bj[S[sum--]]=0;
    35     }
    36     if(sum!=0 || fl==0){printf("ERR
    ");continue;}
    37     int p=0,mx=0,top=0;bool fl1=1;
    38     for(int i=1;i<=n;i++){
    39       if(fl1==0){
    40     int op=1;
    41     while(1){
    42       if(i>n) break;
    43       if(fe[i][0]=='E') op--;
    44       else if(fe[i][0]=='F') op++;
    45       if(op==0) break;
    46       i++;
    47     }
    48     fl1=1;
    49     continue;
    50       }
    51       if(fe[i][0]=='F'){
    52     if(fo[i].y[0]=='n' && fo[i].x[0]=='n'){S[++top]=0;continue;}
    53     else if(fo[i].y[0]=='n'){p++;S[++top]=1;continue;}
    54     else if(fo[i].x[0]=='n'){fl1=0;continue;}
    55     int xx=0,yy=0;
    56     for(U int j=0;j<strlen(fo[i].x);j++) xx=xx*10+fo[i].x[j]-'0';
    57     for(U int j=0;j<strlen(fo[i].y);j++) yy=yy*10+fo[i].y[j]-'0';
    58     if(xx>yy) {fl1=0;continue;}
    59     S[++top]=0;
    60       }
    61       else{mx=max(mx,p);if(S[top])p--;top--;}
    62     }
    63     mx=max(mx,p);
    64     if(mx==0){
    65       if(o[2]=='1') printf("Yes
    ");else printf("No
    ");
    66     }
    67     else{
    68       int zz=0;
    69       if(o[2]=='1'){printf("No
    ");continue;}
    70       for(int j=4;o[j]!=')';j++) zz=zz*10+o[j]-'0';
    71       if(zz==mx) printf("Yes
    ");
    72       else printf("No
    ");
    73     }
    74   }
    75   return 0;
    76 }
    时间复杂度

    逛公园

    首先判-1

    先正反两遍求出最短路.

    然后Tarjan找0环,若从起点到0环的距离到终点的距离<=最短路+k,则-1.

    设f[i][j]表示到了i点,比最短路多了j的路程的方案数,转移就比较显然了.

    拓扑排序被卡常,记忆化搜索跑的贼快.

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<algorithm>
      7 #include<stack>
      8 #include<queue>
      9 #include<set>
     10 #include<vector>
     11 #include<map>
     12 #define maxn 200010
     13 #define mk make_pair
     14 #define fi first
     15 #define se second
     16 #define RG register
     17 using namespace std;
     18 typedef pair<int,int> P;
     19 struct data{
     20   int nex,to,w;
     21 }e[maxn],g[maxn];
     22 int head[maxn],head1[maxn],edge1=0,edge=0,n,m,k,p,dis[maxn],dis1[maxn],f[maxn][55];
     23 int dfn[maxn],low[maxn],de=0,top=0;
     24 int S[maxn];
     25 bool vis[maxn],scc[maxn],flag=0;
     26 queue<int>q;
     27 inline void add(RG int from,RG int to,RG int w){
     28   e[++edge]=(data){head[from],to,w};
     29   head[from]=edge;
     30   g[++edge1]=(data){head1[to],from,w};
     31   head1[to]=edge1;
     32 }
     33 inline void getdis(){
     34   memset(dis,127/3,sizeof(dis));
     35   dis[1]=0,vis[1]=1,q.push(1);
     36   while(!q.empty()){
     37     RG int u=q.front();q.pop(),vis[u]=0;
     38     for(RG int i=head[u];i;i=e[i].nex){
     39       RG int v=e[i].to;
     40       if(dis[v]>dis[u]+e[i].w){
     41     dis[v]=dis[u]+e[i].w;
     42     if(!vis[v]) q.push(v),vis[v]=1;
     43       }
     44     }
     45   }
     46 }
     47 inline void getdis1(){
     48   memset(dis1,127/3,sizeof(dis1));
     49   dis1[n]=0,vis[n]=1,q.push(n);
     50   while(!q.empty()){
     51     RG int u=q.front();q.pop(),vis[u]=0;
     52     for(RG int i=head1[u];i;i=g[i].nex){
     53       RG int v=g[i].to;
     54       if(dis1[v]>dis1[u]+g[i].w){
     55     dis1[v]=dis1[u]+g[i].w;
     56     if(!vis[v]) q.push(v),vis[v]=1;
     57       }
     58     }
     59   }
     60 }
     61 inline void Tarjan(int x){
     62   dfn[x]=low[x]=++de;
     63   S[++top]=x;
     64   for(int i=head[x];i;i=e[i].nex)
     65     if(e[i].w==0){
     66       int v=e[i].to;
     67       if(!dfn[v])Tarjan(v),low[x]=min(low[x],low[v]);
     68       else if(!scc[v]) low[x]=min(low[x],dfn[v]);
     69     }
     70   if(dfn[x]==low[x]){
     71     int sz=1;
     72     while(S[top]!=x) scc[S[top--]]=1,sz++;
     73     top--;scc[x]=1;
     74     if(sz>1 && dis[x]+dis1[x]<=dis[n]+k)flag=1;
     75   }
     76 }
     77 inline bool check(){
     78   flag=0;memset(scc,0,sizeof(scc));
     79   for(int i=1;i<=n;i++)
     80     if(!dfn[i]) Tarjan(i);
     81   return flag;
     82 }
     83 int dfs(int x,int pp){
     84   if(pp<0) return 0;
     85   if(x==n && pp==0) return 1;
     86   if(f[x][pp]!=-1) return f[x][pp];
     87   f[x][pp]=0;
     88   for(int i=head[x];i;i=e[i].nex){
     89     int v=e[i].to;
     90     f[x][pp]+=dfs(v,pp-(e[i].w+dis1[v]-dis1[x]));
     91     if(f[x][pp]>=p) f[x][pp]-=p;
     92   }
     93   return f[x][pp];
     94 }
     95 int main(){
     96   RG int T;
     97   scanf("%d",&T);
     98   while(T){T--;
     99     scanf("%d%d%d%d",&n,&m,&k,&p);
    100     memset(head,0,sizeof(head)),edge=edge1=de=top=0;
    101     memset(head1,0,sizeof(head1));memset(f,-1,sizeof(f));
    102     memset(dfn,0,sizeof(dfn)),memset(low,0,sizeof(low));
    103     for(RG int i=1,x,y,z;i<=m;i++)
    104       scanf("%d%d%d",&x,&y,&z),add(x,y,z);
    105     getdis();getdis1();
    106     if(check()){printf("-1
    ");continue;};
    107     RG int ans=0;
    108     for(RG int i=0;i<=k;i++) ans=(ans+dfs(1,i))%p;
    109     printf("%d
    ",ans);
    110   }
    111   return 0;
    112 }
    逛公园

    奶酪

    用公式算距离然后并查集即可.

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<queue>
     8 #include<vector>
     9 #include<stack>
    10 #include<map>
    11 #include<set>
    12 #define maxn 1010
    13 using namespace std;
    14 double x[maxn],y[maxn],z[maxn],fa[maxn],r;
    15 int find(int x){if(fa[x]!=x)fa[x]=find(fa[x]);return fa[x];}
    16 inline void unionn(int i,int j){
    17   int u=find(i),v=find(j);
    18   if(u!=v) fa[v]=u;
    19 }
    20 inline bool check(int i,int j){
    21   double dis=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]));
    22   if(dis<=2*r) return 1;
    23   else return 0;
    24 }
    25 int main(){
    26   int T,n;double h;
    27   scanf("%d",&T);
    28   while(T){T--;
    29     scanf("%d%lf%lf",&n,&h,&r);
    30     for(int i=1;i<=n;i++)
    31       scanf("%lf%lf%lf",&x[i],&y[i],&z[i]),fa[i]=i;
    32     int s=0,t=n+1;fa[s]=s,fa[t]=t;
    33     for(int i=1;i<=n;i++){
    34       if(z[i]<=r) unionn(s,i);
    35       if(z[i]>=h-r) unionn(t,i);
    36     }
    37     for(int i=1;i<=n;i++)
    38       for(int j=i+1;j<=n;j++)
    39     if(check(i,j)) unionn(i,j);
    40     if(find(s)==find(t)) printf("Yes
    ");
    41     else printf("No
    ");
    42   }
    43   return 0;
    44 }
    奶酪

    宝藏

    感觉是今年正解最难的一道题,不过搜索+剪枝可以过.

    子集DP.

    设f[i][j]表示当前扩展到第i层,已经扩展到的节点集合为j的最小代价.

    转移的话枚举补集,然后暴力算补集中的每个点到现在集合中的点的最小距离.

    复杂度(3^n*n^2)

    可以预处理每个点到每个集合的最短距离,复杂度可以优化一个n.

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<queue>
     8 #include<vector>
     9 #include<stack>
    10 #include<map>
    11 #include<set>
    12 #include<ctime>
    13 #define fi first
    14 #define se second
    15 #define mk make_pair
    16 #define RG register
    17 using namespace std;
    18 int w[15][15],f[15][5010],n,m;
    19 inline int solve(int s0,int s){
    20   int ans=0;
    21   for(int i=0;i<n;i++)
    22     if(s0&(1<<i)){
    23       int zd=500010;
    24       for(int j=0;j<n;j++)
    25     if(s&(1<<j))zd=min(zd,w[i][j]);
    26       ans+=zd;
    27     }
    28   return ans;
    29 }
    30 int main(){
    31   int lim,ans,inf;
    32   scanf("%d%d",&n,&m);lim=(1<<n)-1;
    33   memset(f,127/3,sizeof(f));ans=inf=f[0][0];
    34   for(int i=0;i<n;i++) f[0][1<<i]=0;
    35   for(int i=0;i<n;i++)
    36     for(int j=0;j<n;j++)w[i][j]=500010;
    37   for(RG int i=1,x,y,z;i<=m;i++)
    38     scanf("%d%d%d",&x,&y,&z),x--,y--,w[x][y]=w[y][x]=min(w[x][y],z);
    39   for(int i=0;i<n;i++)
    40     for(int s=0;s<=lim;s++)
    41       if(f[i][s]<inf){
    42     int U=lim^s;
    43     for(int s0=U;s0;s0=(s0-1)&U){
    44       int wp=solve(s0,s);
    45       f[i+1][s0|s]=min(f[i+1][s0|s],f[i][s]+wp*(i+1));
    46     }
    47       }
    48   for(int i=0;i<=n;i++) ans=min(ans,f[i][lim]);
    49   printf("%d",ans);
    50   return 0;
    51 }
    宝藏

    列队

    若想到用"非NOIP"的做法来做还是不太难..

    考场上思维局限在NOIP,导致这题挂烂.

    想到动态开点线段树就比较容易了.

    维护n+1棵线段树,n棵表示行,1棵表示最后一列.

    对于每次出队,分两种情况讨论.

    1.在最后一列出对.

    在出队点的线段树的位置赋为1,表示这个地方已经没有人了.

    然后把这个人插入到后面,往动态数组里面插.

    所以线段树的大小为max(n,m)+q.

    每次在线段树里面查询第k个0的位置即可.

    2.不在最后一列出队.

    把这一行的这个点删除,插入到最后一列最后一个中,然后把最后一列的这一行的删除,并且插入到这一行的最后一个中.

    比平衡树容易实现得多.

    代码十分短.

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<vector>
     8 #include<queue>
     9 #include<stack>
    10 #include<map>
    11 #include<set>
    12 #define maxn 300010
    13 #define LL long long
    14 #define pb push_back
    15 using namespace std;
    16 int mx,n,m,cnt=0,rt[maxn*20],ls[maxn*20],rs[maxn*20],b[maxn*20];
    17 vector<LL>vec[maxn];
    18 void change(int &x,int l,int r,int sp){
    19   if(!x) x=++cnt;b[x]++;
    20   if(l==r) return;
    21   int mid=(l+r)>>1;
    22   if(sp<=mid) change(ls[x],l,mid,sp);
    23   else change(rs[x],mid+1,r,sp);
    24 }
    25 int query(int x,int l,int r,int k){
    26   if(l==r) return l;
    27   int mid=(l+r)>>1,sum=mid-l+1-b[ls[x]];
    28   if(sum>=k) return query(ls[x],l,mid,k);
    29   else return query(rs[x],mid+1,r,k-sum);
    30 }
    31 inline LL calc1(int x){
    32   int r=query(rt[n+1],1,mx,x);
    33   change(rt[n+1],1,mx,r);
    34   return r<=n?(LL)r*m:vec[n+1][r-n-1];
    35 }
    36 inline LL calc2(int x,int y){
    37   int r=query(rt[x],1,mx,y);
    38   change(rt[x],1,mx,r);
    39   return r<m?(LL)(x-1)*m+r:vec[x][r-m];
    40 }
    41 int main(){
    42   freopen("!.in","r",stdin);
    43   freopen("!.out","w",stdout);
    44   int q;
    45   scanf("%d%d%d",&n,&m,&q);
    46   mx=max(n,m)+q;
    47   for(int i=1,x,y;i<=q;i++){
    48     LL ans;
    49     scanf("%d%d",&x,&y);
    50     if(y==m){
    51       ans=calc1(x);
    52       printf("%lld
    ",ans);
    53       vec[n+1].pb(ans);
    54     }
    55     else{
    56       ans=calc2(x,y);
    57       printf("%lld
    ",ans);
    58       LL tmp=calc1(x);
    59       vec[n+1].pb(ans);
    60       vec[x].pb(tmp);
    61     }
    62   }
    63   return 0;
    64 }
    列队
  • 相关阅读:
    数据仓库专题18-数据建模语言IDEF(转载)
    数据仓库专题(14)-数据仓库建设指导原则:一切以就绪数据为主
    数据仓库专题(16)-分布式数据仓库实践指南-目录篇
    解释器模式
    命令模式
    责任链模式
    代理模式
    享元模式
    外观模式
    装饰器模式
  • 原文地址:https://www.cnblogs.com/pantakill/p/7965726.html
Copyright © 2011-2022 走看看