【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\n",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\n",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\n",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\n");
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\n%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\n");
130     }
131     else printf("%lld",ans);
132     return 0;
133   }
134 }
135 signed main(){
136   gengyf::main();
137   return 0;
138 }
T6

 


 

 

我太难了

posted @ 2019-09-18 21:58  喵の耳  阅读(350)  评论(1编辑  收藏  举报