• $NOIP2015$ 题解报告


    目录

    $Luogu P2615$ 神奇的幻方$( √ )$

    $Luogu P2661$ 信息传递$( √ )$

    $Luogu P2668$ 斗地主$( √ )$

    $Luogu P2678$ 跳石头$( √ )$

    $Luogu P2679$ 子串$( √ )$

    $Luogu P2680$ 运输计划$( √ )$


    $Luogu P2615$ 神奇的幻方

    题目传送门

    昂直接模拟就好了

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n;
     4 int square[40][40];
     5 struct Num{
     6     int x,y;
     7 }num[40*40];
     8 void work(int k){
     9     if(num[k-1].x==1&&num[k-1].y!=n)
    10         num[k].x=n,num[k].y=num[k-1].y+1;
    11     if(num[k-1].y==n&&num[k-1].x!=1)
    12         num[k].x=num[k-1].x-1,num[k].y=1;
    13     if(num[k-1].x==1&&num[k-1].y==n)
    14         num[k].x=2,num[k].y=num[k-1].y;
    15     if(num[k-1].x!=1&&num[k-1].y!=n){
    16         if(square[num[k-1].x-1][num[k-1].y+1]==0)
    17             num[k].x=num[k-1].x-1,num[k].y=num[k-1].y+1;
    18         else
    19             num[k].x=num[k-1].x+1,num[k].y=num[k-1].y;
    20     }
    21     square[num[k].x][num[k].y]=k;
    22     return;
    23 }
    24 int main(){
    25     cin>>n;
    26     square[1][n/2+1]=1;
    27     num[1].x=1;
    28     num[1].y=n/2+1;
    29     for(int i=2;i<=n*n;i++)
    30         work(i);
    31     for(int i=1;i<=n;i++){
    32         for(int j=1;j<=n;j++)
    33             cout<<square[i][j]<<" ";
    34         cout<<endl;
    35     }
    36 }
    代码戳这里

    $Luogu P2661$ 信息传递

    题目传送门

    并查集求最小环,如果两个点在一个集合里,那么就构成一个环,长度为两个点到这个集合的父亲节点的距离加上$1$

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=200002;
     4 int n,fa[N],dis[N],minn;
     5 int find(int x){
     6     if(fa[x]!=x){
     7         int last=fa[x];
     8         fa[x]=find(fa[x]);
     9         dis[x]+=dis[last];
    10     }
    11     return fa[x];
    12 }
    13 void check(int x,int y){
    14     int fx=find(x),fy=find(y);
    15     if(fx!=fy) {fa[fx]=fy;dis[x]=dis[y]+1;}
    16     else minn=min(minn,dis[x]+dis[y]+1);
    17     return;
    18 }
    19 int main(){
    20     int i,T;
    21     scanf("%d",&n);
    22     for(i=1;i<=n;i++)
    23         fa[i]=i;
    24     minn=N*2;
    25     for(i=1;i<=n;i++){
    26         scanf("%d",&T);
    27         check(i,T);
    28     }
    29     printf("%d",minn);
    30     return 0;
    31 }
    代码戳这里

    $Luogu P2668$ 斗地主

    题目传送门

    大概是贪心$+$模拟$+dfs$?去年做的了,其实挺恶心

    花色没什么用,我们只需要记录数量。$dfs$过程中,贪心先出顺子,单顺子双顺子三顺子;然后出三带一三带二或者四带二,这里注意就是如果有四张牌先试一下三带一和三带二;最后只要有牌都可以一次把这种牌出完,统计一下答案最小值即可

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define mem(a,b) memset(a,b,sizeof(a));
      4 int n,T,ans;
      5 int num[20];
      6 void search(int times){
      7     if(times>=ans) return;
      8     int len=0;
      9     for(int i=3;i<=14;i++){
     10         if(num[i]==0) {len=0;continue;}
     11         else {
     12           len++;
     13           if(len>=5){
     14               for(int j=i;j>=i-len+1;j--)
     15                   num[j]--;
     16               search(times+1);
     17               for(int j=i;j>=i-len+1;j--)
     18                   num[j]++;
     19           }
     20         }
     21     }
     22     len=0;
     23     for(int i=3;i<=14;i++){
     24         if(num[i]<2) {len=0;continue;}
     25         else{
     26           len++;
     27           if(len>=3){
     28                 for(int j=i;j>=i-len+1;j--)
     29                   num[j]-=2;
     30               search(times+1);
     31               for(int j=i;j>=i-len+1;j--)
     32                   num[j]+=2;
     33           }
     34         }
     35     }
     36     len=0;
     37     for(int i=3;i<=14;i++){
     38         if(num[i]<3) {len=0;continue;}
     39         else{
     40           len++;
     41           if(len>=2){
     42               for(int j=i;j>=i-len+1;j--)
     43                   num[j]-=3;
     44               search(times+1);
     45               for(int j=i;j>=i-len+1;j--)
     46                   num[j]+=3;
     47           }
     48         }
     49     }
     50     for(int i=2;i<=14;i++){
     51         if(num[i]<=2) continue;
     52         if(num[i]==3){
     53             num[i]-=3;
     54             for(int j=2;j<=15;j++){
     55                 if(num[j]==0||i==j) continue;
     56                 num[j]--;
     57                 search(times+1);
     58                 num[j]++;
     59             }
     60             for(int j=2;j<=14;j++){
     61                 if(num[j]<2||i==j) continue;
     62                 num[j]-=2;
     63                 search(times+1);
     64                 num[j]+=2;
     65             }
     66             num[i]+=3;
     67         }
     68         else{
     69             num[i]-=3;
     70             for(int j=2;j<=15;j++){
     71                 if(num[j]==0||i==j) continue;
     72                 num[j]--;
     73                 search(times+1);
     74                 num[j]++;
     75             }
     76             for(int j=2;j<=14;j++){
     77                 if(num[j]<2||i==j) continue;
     78                 num[j]-=2;
     79                 search(times+1);
     80                 num[j]+=2;
     81             }
     82             num[i]--;
     83             for(int j=2;j<=15;j++){
     84                 if(num[j]==0||i==j) continue;
     85                 num[j]--;
     86                 for(int k=2;k<=15;k++){
     87                     if(num[k]==0||i==k) continue;
     88                     num[k]--;
     89                     search(times+1);
     90                     num[k]++;
     91                 }
     92                 num[j]++;
     93             }
     94             for(int j=2;j<=14;j++){
     95                 if(num[j]<2||i==j) continue;
     96                 num[j]-=2;
     97                 for(int k=2;k<=14;k++){
     98                     if(num[k]<2||i==k) continue;
     99                     num[k]-=2;
    100                     search(times+1);
    101                     num[k]+=2;
    102                 }
    103                 num[j]+=2;
    104             }
    105             num[i]+=4;
    106         }
    107     }
    108     for(int i=2;i<=15;i++)
    109         if(num[i]) times++;
    110     ans=min(ans,times);
    111 }
    112 int main(){
    113     scanf("%d%d",&T,&n);
    114     while(T--){
    115         mem(num,0);
    116         ans=30;
    117         int a,b;
    118         for(int i=1;i<=n;i++){
    119             scanf("%d%d",&a,&b);
    120             if(a==0) a=15;
    121             if(a==1) a=14;
    122             num[a]++;
    123         }
    124         search(0);
    125         printf("%d
    ",ans);
    126     }
    127 }
    代码戳这里

    $Luogu P2678$ 跳石头

    题目传送门

    二分答案,然后$check$过程中求出能留下的石子数

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int l,n,m,d[50002];
     4 int fr(){
     5     int w=0,q=1;
     6     char ch=getchar();
     7     while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
     8     if(ch=='-') q=-1;
     9     while(ch<='9'&&ch>='0') w=w*10+ch-'0',ch=getchar();
    10     return w*q;
    11 }
    12 int maxn=0;
    13 bool pd(int x){
    14     int now=0,num=0,next=0;
    15     while(next<n+1){
    16         next++;
    17         if(d[next]-d[now]<x)
    18             num++;
    19         else now=next;
    20     }
    21     //cout<<"x="<<x<<" num="<<num<<endl;
    22     if(num>m) return 0;
    23     else return 1;
    24 }
    25 int main(){
    26     l=fr();n=fr();m=fr();
    27     for(int i=1;i<=n;i++)
    28         d[i]=fr();
    29     d[n+1]=l;
    30     int L=1,R=l;
    31     while(L<=R){
    32         int mid=(L+R)/2;
    33         //cout<<"mid="<<mid<<endl;
    34         if(pd(mid)){
    35             L=mid+1;
    36             maxn=mid;
    37             //cout<<mid<<" "<<maxn<<endl;
    38         }
    39         else R=mid-1;
    40         //cout<<"L="<<L<<" R="<<R<<endl;
    41     }
    42     printf("%d",maxn);
    43     return 0;
    44 }
    代码戳这里

    $Luogu P2679$ 子串

    题目传送门

    $DP$,我还有点地方没搞懂,缓一缓先$QAQ$

     1 #include<bits/stdc++.h>
     2 #define ri register int
     3 #define ll long long
     4 #define rl register ll
     5 #define go(i,a,b) for(ri i=a;i<=b;i++)
     6 #define back(i,a,b) for(ri i=a;i>=b;i--)
     7 #define g() getchar()
     8 #define il inline
     9 #define pf printf
    10 #define mem(a,b) memset(a,b,sizeof(a))
    11 using namespace std;
    12 il int fr(){
    13     ri w=0,q=1;char ch=g();
    14     while(ch<'0'||ch>'9'){if(ch=='-')q=-1;ch=g();}
    15     while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=g();
    16     return w*q;
    17 }
    18 const int M=202;
    19 const int N=1002;
    20 const int mod=1000000007;
    21 int n,m,K;
    22 ll f[M][M],s[M][M];
    23 char a[N],b[M];
    24 int main(){
    25     //freopen(".in","r",stdin);
    26     //freopen(".out","w",stdout);
    27     n=fr();m=fr();K=fr();f[0][0]=1;
    28     scanf("%s",a);scanf("%s",b);
    29     go(i,1,n)back(j,m,1)back(k,K,1)//这儿为什么是倒序昂?QAQ
    30         f[j][k]=(f[j][k]+(s[j][k]=(a[i-1]==b[j-1]?s[j-1][k]+f[j-1][k-1]:0)))%mod;
    31     pf("%lld
    ",f[m][K]);
    32     return 0;
    33 }
    代码戳这里

    $Luogu P2680$ 运输计划

    题目传送门

    首先预处理出每条路径的两个端点,长度和$lca$,然后二分答案。$check$的时候把每个长度大于$mid$的路径利用树上差分求出每条边经过了几次,其中$dif[i]$表示的是$i$节点与其父亲之间的边的值。然后如果有一条边满足所有大于$mid$的路径都经过了,并且这条路径的边权$ge$最长的路径长度$-mid$,这个$mid$就是合法的

     1 #include<bits/stdc++.h>
     2 #define ri register int
     3 #define ll long long
     4 #define rl register ll
     5 #define go(i,a,b) for(ri i=a;i<=b;i++)
     6 #define back(i,a,b) for(ri i=a;i>=b;i--)
     7 #define g() getchar()
     8 #define il inline
     9 #define pf printf
    10 #define mem(a,b) memset(a,b,sizeof(a))
    11 #define E(i,x) for(ri i=hd[x];i;i=e[i].nxt)
    12 #define t(i) e[i].to
    13 using namespace std;
    14 il int fr(){
    15     ri w=0,q=1;char ch=g();
    16     while(ch<'0'||ch>'9'){if(ch=='-')q=-1;ch=g();}
    17     while(ch>='0'&&ch<='9')w=(w<<1)+(w<<3)+ch-'0',ch=g();
    18     return w*q;
    19 }
    20 const int N=300002;
    21 const int INF=1e9+7;
    22 int n,m,hd[N],ed,dif[N],f[N][20],dep[N];
    23 int ans,l,r,dis[N];
    24 struct edge{
    25     int nxt,to,w;
    26 }e[N<<1];
    27 struct line{
    28     int lca,x,y,len;
    29 }L[N];
    30 il void build(int x,int y,int w){e[++ed]=(edge){hd[x],y,w};hd[x]=ed;return;}
    31 il void Tree(int x,int fa){
    32     f[x][0]=fa;dep[x]=dep[fa]+1;
    33     go(i,1,19)f[x][i]=f[f[x][i-1]][i-1];
    34     E(i,x){
    35         if(t(i)==fa)continue;
    36         dis[t(i)]=dis[x]+e[i].w;Tree(t(i),x);
    37     }
    38     return;
    39 }
    40 il int LCA(int x,int y){
    41     if(dep[x]<dep[y])swap(x,y);
    42     back(i,19,0)if(dep[f[x][i]]>=dep[y])x=f[x][i];
    43     if(x==y)return x;
    44     back(i,19,0)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    45     return f[x][0];
    46 }
    47 il void dfs(int x,int fa){
    48     E(i,x){
    49         if(t(i)==fa)continue;
    50         dfs(t(i),x);dif[x]+=dif[t(i)];
    51     }
    52     return;
    53 }
    54 il bool check(int x){
    55     mem(dif,0);int num=0,mx=0;
    56     go(i,1,m){
    57         if(L[i].len<=x)continue;num++;mx=max(mx,L[i].len-x);
    58         dif[L[i].x]++;dif[L[i].y]++;dif[L[i].lca]-=2;
    59     }
    60     dfs(1,0);
    61     //go(i,1,n)cout<<"dif="<<dif[i]<<" dis="<<dis[i]-dis[f[i][0]]<<endl;
    62     go(i,2,n)if(dif[i]==num&&dis[i]-dis[f[i][0]]>=mx)return 1;
    63     return 0;
    64 }
    65 int main(){
    66     //freopen(".in","r",stdin);
    67     //freopen(".out","w",stdout);
    68     n=fr();m=fr();
    69     go(i,1,n-1){
    70         int x=fr(),y=fr(),w=fr();
    71         build(x,y,w);build(y,x,w);
    72     }
    73     Tree(1,0);
    74     go(i,1,m){
    75         int x=fr(),y=fr();
    76         L[i].lca=LCA(x,y);L[i].x=x;L[i].y=y;
    77         L[i].len=dis[x]+dis[y]-2*dis[L[i].lca];
    78         r=max(r,L[i].len);
    79     }
    80     while(l<=r){
    81         int mid=(l+r)>>1;
    82         //cout<<"l="<<l<<" r="<<r<<" mid="<<mid<<endl;
    83         if(check(mid))ans=mid,r=mid-1;
    84         else l=mid+1;
    85     }
    86     pf("%d
    ",ans);
    87     return 0;
    88 }
    代码戳这里
  • 相关阅读:
    zTree 优秀的jquery树插件
    The underlying provider failed on open 问题解决
    HTML 5 <input> list 属性
    C#拖曳控件加载,bll报错问题
    把VS2010的智能代码提示和注解从英文变成中文
    progressBar的使用
    C++内存读写例子
    bash 管理小脚本
    KVM虚拟机配置笔记
    Ettercap 实施中间人攻击
  • 原文地址:https://www.cnblogs.com/THWZF/p/11811982.html
Copyright © 2020-2023  润新知