• 【NOIp】NOIp2012


    NOIp 2012

    day 1 T1 Vigenère 密码

    标签:模拟

    主要是用了ASCII码,字母'A'的ASCII码是41H(0100 0001B),字母'a'的ASCII码是61H(0110 0001B),字母'A'与'a'的二进制后5位是相同的,所以无论是大写字母还是小写字母x,x &31(1 1111B)的值就是x在字母表里的顺序。

    简单判一下边界就行了

    code

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 namespace gengyf{
     4 #define ll long long
     5   inline int read(){
     6     int x=0,f=1;char s=getchar();
     7     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
     8     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
     9     return f*x;
    10   }
    11   char k[110],s[1010];
    12   int main(){
    13     cin>>k>>s;
    14     int lk=strlen(k),ls=strlen(s);
    15     for(int i=0;i<ls;i++){
    16       int t=(k[i%lk]&31)-1;
    17       s[i]=(s[i]&31)-t>0?s[i]-t:s[i]-t+26;
    18     }
    19     cout<<s;
    20     return 0;
    21   }
    22 }
    23 signed main(){
    24   gengyf::main();
    25   return 0;
    26 }
    T1

    day 1 T2 国王游戏

    标签:贪心,高精度

    又是一波证明......

       king:    a0  b0

    player1:   a1   b1

    player2:  a2   b2

    这种情况下,$ans_1=max(a0/b1,a0*a1/b2)$

       king:    a0  b0

    player2:   a2  b2

    player1:    a1  b1

    $ans_2=max(a0/b2,a0*a2/b1)$

    显然$a0*a2/b1 > a0/b1$,$a0*a2/b1 > a0/b1$

    如果$ans_1$<$ans_2$可知$a0*a2/b1$>$a0*a1/b2$ => $a1*b1<a2*b2$

    即$a1*b1<a2*b2$时,$ans_1$<$ans_2$

    所以将${a_i}*{b_i}$较小的放在前面更优

    code

     1 //
     2 //  main.cpp
     3 //  Luogu
     4 //
     5 //  Created by gengyf on 2019/7/10.
     6 //  Copyright © 2019 yifan Geng. All rights reserved.
     7 //
     8 
     9 #include <bits/stdc++.h>
    10 using namespace std;
    11 int sum[20010],now[20010],ans[20010],add[20010];
    12 int n;
    13 struct Node{
    14     int a,b;
    15     long long ab;
    16 }node[1010];
    17 void multi(int x){
    18     memset(add,0,sizeof(add));
    19     for(int i=1;i<=ans[0];i++){
    20         ans[i]*=x;
    21         add[i+1]+=ans[i]/10;
    22         ans[i]%=10;
    23     }
    24     for(int i=1;i<=ans[0]+4;i++){
    25         ans[i]+=add[i];
    26         if(ans[i]>=10){
    27             ans[i+1]+=ans[i]/10;
    28             ans[i]%=10;
    29         }
    30         if(ans[i]!=0){
    31             ans[0]=max(ans[0],i);
    32         }
    33     }
    34 }
    35 int divid(int x){
    36     memset(add,0,sizeof(add));
    37     int q=0;
    38     for(int i=ans[0];i>=1;i--){
    39         q*=10;
    40         q+=ans[i];
    41         add[i]=q/x;
    42         if(add[0]==0&&add[i]!=0){
    43             add[0]=i;
    44         }
    45         q%=x;
    46     }
    47     return 0;
    48 }
    49 bool compar(){
    50     if(sum[0]==add[0]){
    51         for(int i=add[0];i>=1;i--){
    52             if(add[i]>sum[i]) return 1;
    53             if(add[i]<sum[i]) return 0;
    54         }
    55     }
    56     if(add[0]>sum[0]) return 1;
    57     if(add[0]<sum[0]) return 0;
    58 }
    59 void cp(){
    60     memset(sum,0,sizeof(sum));
    61     for(int i=add[0];i>=0;i--){
    62         sum[i]=add[i];
    63     }
    64 }
    65 bool cmp(Node x,Node y){
    66     return x.ab<y.ab;
    67 }
    68 int main(){
    69     scanf("%d",&n);
    70     for(int i=0;i<=n;i++){
    71         scanf("%d%d",&node[i].a,&node[i].b);
    72         node[i].ab=node[i].a*node[i].b;
    73     }
    74     sort(node+1,node+1+n,cmp);
    75     ans[0]=1;ans[1]=1;
    76     for(int i=1;i<=n;i++){
    77         multi(node[i-1].a);
    78         divid(node[i].b);
    79         if(compar()){
    80             cp();
    81         }
    82     }
    83     for(int i=sum[0];i>=1;i--){
    84         printf("%d",sum[i]);
    85     }
    86     return 0;
    87 }
    T2

    day 1 T3 开车旅行

    标签:倍增,dp,STL,预处理

    模拟开车过程,set预处理离城市第一近和第二近的,倍增优化

    $g[i][j]=g[g[i][j-1]][j-1]$

    $f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0]$

    $f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1]$ 

    code(有注释)

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 namespace gengyf{
      4 #define ll long long
      5   inline int read(){
      6     int x=0,f=1;char s=getchar();
      7     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
      8     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
      9     return f*x;
     10   }
     11   const int maxn=100010;
     12   struct node{
     13     int num,h;
     14     bool operator < (const node a) const{
     15       return h<a.h;
     16     }
     17   }c[maxn];
     18   set<node>s;
     19   set<node>::iterator it;
     20   ll f[maxn][25][2];
     21   int nxt[maxn][2],g[maxn][25],dis[maxn][21];
     22   int n,x0,m;
     23   /*
     24    g[i][j]从i开始,两人轮流开2^j轮车后最后到达的位置
     25    f[i][j][0]从i开始,两人轮流开2^j轮车后小A走的距离
     26    f[i][j][1]从i开始,两人轮流开2^j轮车后小B走的距离
     27    nxt[i][0]离i第一近的城市编号
     28    nxt[i][1]离i第二近的城市编号
     29    dis[i][0]离i第一近的城市到i的距离
     30    dis[i][1]离i第二近的城市到i的距离
     31    */
     32   void update(node x,node y){
     33     if(!nxt[x.num][0]){
     34       nxt[x.num][0]=y.num;
     35       dis[x.num][0]=abs(x.h-y.h);
     36     }
     37     else if(dis[x.num][0]>abs(x.h-y.h)||(dis[x.num][0]==abs(x.h-y.h)&&y.h<c[nxt[x.num][0]].h)){
     38       nxt[x.num][1]=nxt[x.num][0];
     39       dis[x.num][1]=dis[x.num][0];
     40       nxt[x.num][0]=y.num;
     41       dis[x.num][0]=abs(x.h-y.h);
     42     }
     43     else if(dis[x.num][1]>abs(x.h-y.h)||(dis[x.num][1]==abs(x.h-y.h)&&y.h<c[nxt[x.num][1]].h)){
     44       nxt[x.num][1]=y.num;
     45       dis[x.num][1]=abs(x.h-y.h);
     46     }
     47     else if(!nxt[x.num][1]){
     48       nxt[x.num][1]=y.num;
     49       dis[x.num][1]=abs(x.h-y.h);
     50     }
     51     return;
     52   }
     53   void query(int s,int x,ll &disa,ll &disb){
     54     for(int i=20;i>=0;i--){
     55       if(f[s][i][0]+f[s][i][1]<=x&&g[s][i]){
     56         disa+=f[s][i][0];
     57         disb+=f[s][i][1];
     58         x-=f[s][i][1]+f[s][i][0];
     59         s=g[s][i];
     60       }
     61     }
     62     if(nxt[s][1]&&dis[s][1]<=x){
     63       disa+=dis[s][1];
     64     }
     65   }
     66   int main(){
     67     n=read();
     68     for(int i=1;i<=n;i++){
     69       c[i].h=read();c[i].num=i;
     70     }
     71     for(int i=n;i>=1;i--){
     72       s.insert(c[i]);
     73       it=s.find(c[i]);
     74       if(it!=s.begin()){
     75         it--;
     76         update(c[i],*it);
     77         if(it!=s.begin()){
     78           it--;
     79           update(c[i],*it);
     80           it++;
     81         }
     82         it++;
     83       }
     84       if((++it)!=s.end()){
     85         update(c[i],*it);
     86         if((++it)!=s.end()){
     87           update(c[i],*it);
     88           it--;
     89         }
     90         it--;
     91       }
     92     }
     93     for(int i=1;i<=n;i++){
     94       g[i][0]=nxt[nxt[i][1]][0];
     95       f[i][0][0]=dis[i][1];
     96       f[i][0][1]=dis[nxt[i][1]][0];
     97     }
     98     for(int j=1;j<=20;j++)
     99       for(int i=1;i<=n;i++){
    100         g[i][j]=g[g[i][j-1]][j-1];
    101         f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
    102         f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
    103       }
    104     x0=read();ll s0=0,a=1e15,b=0;
    105     for(int i=1;i<=n;i++){
    106       ll disa=0,disb=0;
    107       query(i,x0,disa,disb);
    108       if(disb&&(!s0||disa*b<disb*a)){
    109         s0=i;a=disa;b=disb;
    110       }
    111     }
    112     printf("%lld
    ",s0);
    113     m=read();
    114     while(m--){
    115       ll disa=0,disb=0;
    116       int s,x;
    117       s=read();x=read();
    118       query(s,x,disa,disb);
    119       printf("%lld %lld
    ",disa,disb);
    120     }
    121     return 0;
    122   }
    123 }
    124 signed main(){
    125   gengyf::main();
    126   return 0;
    127 }
    T3

     写链表的都是神仙

    day 2 T1 同余方程

    标签:数论

    对于方程$a*x≡1(mod b)$,等价于$a*x+b*y=1$

    用exgcd解线性方程,见我之前的博客(不要脸行为

    code

     1 //
     2 //  main.cpp
     3 //  Luogu
     4 //
     5 //  Created by gengyf on 2019/5/7.
     6 //  Copyright © 2019 yifan Geng. All rights reserved.
     7 //
     8 
     9 #include<cstdio>
    10 #include<iostream>
    11 #include<cstring>
    12 #include<string>
    13 //#include<bits/stdc++.h>
    14 using namespace std;
    15 long long a,b,x,y;
    16 void exgcd(long xx,long yy){
    17     if(yy==0){
    18         x=1;y=0;return ;
    19     }
    20     exgcd(yy,xx%yy);
    21     long long tx=x;
    22     x=y;
    23     y=tx-xx/yy*y;
    24 }
    25 int main(){
    26     scanf("%lld%lld",&a,&b);
    27     exgcd(a,b);
    28     while(x<0){
    29         x+=b;
    30         x%=b;
    31     }
    32     printf("%lld
    ",x);
    33 }
    T4

    day 2 T2 借教室

    标签:二分

     利用差分的思想,当一个区间+x时,只需在l处+x,r+1处-x

    显然如果一个人不能满足,后面都不能满足,如果可以满足,前面一定都能满足,符合二分性质

    code

     1 //
     2 //  main.cpp
     3 //  Luogu
     4 //
     5 //  Created by gengyf on 2019/7/11.
     6 //  Copyright © 2019 yifan Geng. All rights reserved.
     7 //
     8 
     9 #include <bits/stdc++.h>
    10 using namespace std;
    11 #define maxn 1000010
    12 int d[maxn],s[maxn],t[maxn];
    13 int b[maxn],n,m,need[maxn],a[maxn];
    14 bool check(int x){
    15     memset(b,0,sizeof(b));
    16     for(int i=1;i<=x;i++){
    17         b[s[i]]+=d[i];
    18         b[t[i]+1]-=d[i];
    19     }
    20     for(int i=1;i<=n;i++){
    21         need[i]=need[i-1]+b[i];
    22         if(need[i]>a[i])return 0;
    23     }
    24     return 1;
    25 }
    26 int main(){
    27     scanf("%d%d",&n,&m);
    28     for(int i=1;i<=n;i++){
    29         scanf("%d",&a[i]);
    30     }
    31     for(int i=1;i<=m;i++){
    32         scanf("%d%d%d",&d[i],&s[i],&t[i]);
    33     }
    34     int l=1,r=m;
    35     if(check(m)){
    36         printf("0
    ");
    37         return 0;
    38     }
    39     while(l<r){
    40         int mid=(l+r)/2;
    41         if(check(mid)){
    42             l=mid+1;
    43         }
    44         else r=mid;
    45     }
    46     printf("-1
    %d",l);
    47     return 0;
    48 }
    T5

    day 2 T3 疫情控制

    标签:倍增,贪心

    离根越近,能被叶节点到根的路径经过的越多,所以要在时间允许的范围内尽量把军队向根靠近

    上提军队用倍增优化,要求的是最短的移动最多的军队所需时间,二分求解

    如果调了很久调不出来,那就重构

    code(大概是有注释,如果没有那就是咕了)

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 namespace gengyf{
      4 #define ll long long
      5   inline int read(){
      6     int x=0,f=1;char s=getchar();
      7     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
      8     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
      9     return f*x;
     10   }
     11   const int maxn=50010;
     12   struct edge{
     13     int nxt,to,w;
     14   }e[maxn*4];
     15   int n,m,q[maxn];
     16   int head[maxn],cnt,d[maxn],f[maxn][25],t;
     17   bool st[maxn],need[maxn],fl;
     18   ll dis[maxn][25],tim[maxn],ned[maxn],ans;
     19   pair<ll,int>h[maxn];
     20   //q[]输入军队,f[i][j]存i的2^j祖先是谁,dis[i][j]存i到i的2^j祖先的路径长度
     21   //d[]深度,st[]驻扎军队,need[]需要驻扎,tim[]军队剩余时间,ned[]仍需驻扎
     22   void add(int from,int to,int w){
     23     e[++cnt].to=to;e[cnt].nxt=head[from];
     24     head[from]=cnt;e[cnt].w=w;
     25   }
     26   void dfs(){
     27     queue<int>q;
     28     q.push(1);d[1]=1;
     29     while(q.size()){
     30       int x=q.front();q.pop();
     31       for(int i=head[x];i;i=e[i].nxt){
     32         int y=e[i].to;
     33         if(d[y])continue;
     34         d[y]=d[x]+1;
     35         f[y][0]=x;dis[y][0]=e[i].w;
     36         for(int j=1;j<=t;j++){//倍增
     37           f[y][j]=f[f[y][j-1]][j-1];
     38           dis[y][j]=dis[y][j-1]+dis[f[y][j-1]][j-1];
     39         }
     40         q.push(y);
     41       }
     42     }
     43   }
     44   bool dfs2(int x){
     45     bool pson=0;//判断是否为叶节点
     46     if(st[x])return 1;//是否已经驻扎
     47     for(int i=head[x];i;i=e[i].nxt){
     48       int y=e[i].to;
     49       if(d[x]>d[y])continue;
     50       pson=1;//不是叶节点
     51       if(!dfs2(y)){
     52         return 0;
     53       }
     54     }
     55     if(!pson)return 0;//当前节点是叶子节点且未被驻扎
     56     return 1;//没有遇到路径未被驻扎的叶子节点
     57   }
     58   bool check(ll lim){//lim当前实现
     59     memset(st,0,sizeof(st));
     60     memset(tim,0,sizeof(tim));
     61     memset(need,0,sizeof(need));
     62     memset(h,0,sizeof(h));
     63     memset(ned,0,sizeof(ned));
     64     int atot=0,btot=0,ctot=1;
     65     for(int i=1;i<=m;i++){
     66       ll x=q[i],tot=0;//tot总共用多少时间
     67       for(int j=t;j>=0;j--)
     68         if(f[x][j]>1 && tot+dis[x][j]<=lim){//若终点在根节点之前且不会超过时限
     69           tot+=dis[x][j];
     70           x=f[x][j];
     71         }
     72       if(f[x][0]==1 && tot+dis[x][0]<=lim)//若当前节点为根节点的子节点且该军队可以在时限内到达根节点
     73         h[++ctot]=make_pair(lim-tot-dis[x][0],x);//存储闲置军队
     74       else
     75         st[x]=1;//标记驻扎
     76     }
     77     for(int i=head[1];i;i=e[i].nxt){//遍历整棵树
     78       if(!dfs2(e[i].to)){//若需要被驻扎
     79         need[e[i].to]=1;
     80       }
     81     }
     82     sort(h+1,h+1+ctot);
     83     for(int i=1;i<=ctot;i++){//遍历所有闲置的军队
     84       if(need[h[i].second] && h[i].first<dis[h[i].second][0])//若该军队所处的节点需要被驻扎且该军队无法到达根节点并返回
     85         need[h[i].second]=0;
     86       else tim[++atot]=h[i].first;//存储军队的剩余时间
     87     }
     88     for(int i=head[1];i;i=e[i].nxt){
     89       if(need[e[i].to]){//如果仍需要被驻扎
     90         ned[++btot]=dis[e[i].to][0];
     91       }
     92     }
     93     if(atot<btot)return 0;//如果剩余的军队比需要被驻扎的节点还少,不可行,直接返回0
     94     sort(tim+1,tim+atot+1);
     95     sort(ned+1,ned+btot+1);
     96     int i=1,j=1;
     97     while(i<=btot&&j<=atot){
     98       if(tim[j]>=ned[i]){//可行
     99         i++;j++;
    100       }
    101       else j++;
    102     }
    103     if(i>btot)return 1;//所有需要被驻扎的节点都已被驻扎
    104     return 0;
    105   }
    106   int main(){
    107     ll l=0,r=0;
    108     n=read();
    109     t=log2(n)+1;//倍增
    110     for(int i=1;i<n;i++){
    111       int u,v,w;
    112       u=read();v=read();w=read();
    113       add(u,v,w);add(v,u,w);
    114       r+=w;
    115     }
    116     dfs();
    117     cin>>m;
    118     for(int i=1;i<=m;i++){
    119       q[i]=read();
    120     }
    121     while(l<=r){
    122       ll mid=(l+r)>>1;
    123       if(check(mid)){
    124         r=mid-1;ans=mid;fl=1;//fl有解
    125       }
    126       else l=mid+1;
    127     }
    128     if(!fl){
    129       printf("-1
    ");
    130     }
    131     else printf("%lld",ans);
    132     return 0;
    133   }
    134 }
    135 signed main(){
    136   gengyf::main();
    137   return 0;
    138 }
    T6

    我太难了

  • 相关阅读:
    软件项目版本号的命名规则及格式介绍
    软件项目版本号的命名规则及格式介绍
    够用一辈子的几句话
    十四个ASP.NET基础知识问答(C#版)
    够用一辈子的几句话
    够用一辈子的几句话
    软件项目版本号的命名规则及格式介绍
    leveldb java 版本
    Java List 的merge
    HBase 之mapreduce 提升
  • 原文地址:https://www.cnblogs.com/gengyf/p/11544297.html
Copyright © 2020-2023  润新知