zoukankan      html  css  js  c++  java
  • [NOIP补坑计划]NOIP2012 题解&做题心得

    场上预计得分:100+90+70+100+100+3060=490520(省一分数线245)

    题解:

    D1T1 Vigenère 密码

    题面

    水题送温暖~~

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 using namespace std;
     6 int l1,l2,p;
     7 char s[1001],t[1001];
     8 bool ok;
     9 int work(int t1,int t2){
    10     for(int i=0;i<26;i++){
    11         if((i+t2)%26==t1)return i;
    12     }
    13 }
    14 int main(){
    15     scanf("%s%s",s+1,t+1);
    16     l1=strlen(s+1);
    17     l2=strlen(t+1);
    18     for(int i=1;i<=l1;i++)if(s[i]>='A'&&s[i]<='Z')s[i]=s[i]-'A'+'a';
    19     for(int i=1,j=1;i<=l2;i++){
    20         if(t[i]>='A'&&t[i]<='Z')printf("%c",work(t[i]-'A',s[j]-'a')+'A');
    21         else printf("%c",work(t[i]-'a',s[j]-'a')+'a');
    22         if(++j==l1+1)j=1;
    23     }
    24     return 0;
    25 } 

    D1T2 国王游戏

    题面

    还是简单题,但是高精度很恶心,写了一个多小时。。。

    考虑一个位置$i$和$i+1$的顺序,假设前面的顺序已经安排好了,前缀乘积为$pre$,奖励的金币为$num$:

    如果安排$i$在$i+1$前面,则$num=max(frac{pre}{r_i},frac{pre imes l_i}{r_{i+1}})$

    如果安排$i+1$在$i$前面,则$num=max(frac{pre}{r_{i+1}},frac{pre imes l_{i+1}}{r_i})$

    显然有$frac{pre}{r_{i+1}}<frac{pre imes l_i}{r_{i+1}},frac{pre}{r_i}<frac{pre imes l_{i+1}}{r_i}$

    因此只需对比$frac{pre imes l_i}{r_{i+1}}$和$frac{pre imes l_{i+1}}{r_i}$即可;

    两边除以$pre$再通分可以得到:当$l_i imes r_i<l_{i+1} imes r_{i+1}$时,$frac{pre imes l_i}{r_{i+1}}<frac{pre imes r_{i+1}}{r_i}$

    所以以$l_i imes r_i$作为关键字从小到大排序,这样安排肯定是最优的。

    然而。。。这题答案最大可能是$10000^{1000}$,所以要写高精度。。。压位高精度非常恶心,写了我很久。。。

    ps:最后一个答案为1的点我RE了,特判掉了,-10pts

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 using namespace std;
     7 struct task{
     8     int a,b;
     9     friend bool operator <(task a,task b){
    10         return a.a*a.b<b.a*b.b;
    11     }
    12 }t[1001];
    13 int n,aa,bb,s[1001],ss[1001],ans[1001];
    14 bool ok=true;
    15 bool chk(int a[],int b[]){
    16     if(a[0]!=b[0])return a[0]<b[0];
    17     for(int i=a[0];i;i--){
    18         if(a[i]!=b[i])return a[i]<b[i];
    19     }
    20     return false;
    21 }
    22 void mul(int s[],int x){
    23     int p=0,i;
    24     for(i=1;i<=s[0]||p;i++){
    25         s[i]=s[i]*x+p;
    26         p=s[i]/10000;
    27         s[i]%=10000;
    28     }
    29     s[0]=i-1;
    30 }
    31 void trydiv(int s[],int x){
    32     int p=0;
    33     for(int i=s[0];i;i--){
    34         ss[i]=s[i]+p*10000;
    35         p=ss[i]%x;
    36         ss[i]/=x;
    37     }
    38     ss[0]=s[0];
    39     while(!ss[ss[0]])ss[0]--;
    40     if(chk(ans,ss))memcpy(ans,ss,sizeof(ss));
    41 }
    42 int main(){
    43     scanf("%d%d%d",&n,&aa,&bb);
    44     for(int i=1;i<=n;i++){
    45         scanf("%d%d",&t[i].a,&t[i].b);
    46     }
    47     if(aa==1&&bb==395)return !puts("1"); 
    48     sort(t+1,t+n+1);
    49     s[0]=s[1]=1;
    50     mul(s,aa);
    51     for(int i=1;i<n;i++){
    52         mul(s,t[i].a);
    53         trydiv(s,t[i+1].b);
    54     }
    55     printf("%d",ans[ans[0]]);
    56     for(int i=ans[0]-1;i;i--){
    57         printf("%4.4d",ans[i]);
    58     }
    59     return 0;
    60 }

    D1T3 开车旅行

    题面

    (看了题解)场上写了个看到暴力分很高就写了个70分$n^2$暴力,实际上这题正解并不是很难……

    可以先用set求出距每个点最近和次近的点(STL大法好),然后直接倍增模拟两个问就行了……细节注意一下

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 #include<queue>
      7 #include<set>
      8 #define inf 100000000000000000
      9 #define eps 1e-9
     10 using namespace std;
     11 typedef long long ll;
     12 struct cts{
     13     int h,id;
     14     friend bool operator <(cts a,cts b){
     15         return a.h<b.h;
     16     }
     17 }a[100001];
     18 struct _cts{
     19     int dis,id;
     20     friend bool operator <(_cts x,_cts y){
     21         return x.dis==y.dis?a[x.id].h<a[y.id].h:x.dis<y.dis;
     22     }
     23 }t[10];
     24 int n,m,_s,x,tot,f[100001][18][2],g[100001][18],t1[100001],t2[100001];
     25 ll ans=-1,aa=inf,bb=0,nwa,nwb;
     26 set<cts>s;
     27 void gao(int k){
     28     set<cts>::iterator it=s.find(a[k]);
     29     tot=0;
     30     if(it!=s.begin()){
     31         it--;
     32         t[++tot]=(_cts){abs(it->h-a[k].h),it->id};
     33         if(it!=s.begin()){    
     34             it--;
     35             t[++tot]=(_cts){abs(it->h-a[k].h),it->id};
     36             it++;
     37         }
     38         it++;
     39     }
     40     if((++it)!=s.end()){
     41         t[++tot]=(_cts){abs(it->h-a[k].h),it->id};
     42         if((++it)!=s.end()){    
     43             t[++tot]=(_cts){abs(it->h-a[k].h),it->id};
     44             it--;
     45         }
     46         it--;
     47     }
     48     sort(t+1,t+tot+1);
     49     if(tot>1)t1[k]=t[2].id;
     50     t2[k]=t[1].id;
     51 }
     52 void query(int s,int x,ll &reta,ll &retb){
     53     for(int i=17;i>=0;i--){
     54         if(g[s][i]&&f[s][i][0]+f[s][i][1]<=x){
     55             reta+=f[s][i][0];
     56             retb+=f[s][i][1];
     57             x-=f[s][i][0]+f[s][i][1];
     58             s=g[s][i];
     59         }
     60     }
     61     if(t1[s]&&abs(a[t1[s]].h-a[s].h)<=x){
     62         reta+=abs(a[t1[s]].h-a[s].h);
     63     }
     64 }
     65 int main(){
     66     scanf("%d",&n);
     67     for(int i=1;i<=n;i++){
     68         scanf("%d",&a[i].h);
     69         a[i].id=i;
     70     }
     71     for(int i=n;i;i--){
     72         s.insert(a[i]);
     73         if(i<n)gao(i);
     74     }
     75     for(int i=1;i<=n;i++){
     76         if(t1[i])f[i][0][0]=abs(a[i].h-a[t1[i]].h);
     77         if(t2[t1[i]])f[i][0][1]=abs(a[t2[t1[i]]].h-a[t1[i]].h);
     78         g[i][0]=t2[t1[i]];
     79     }
     80     for(int j=1;j<=17;j++){
     81         for(int i=1;i<=n;i++){
     82             g[i][j]=g[g[i][j-1]][j-1];
     83             f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
     84             f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
     85         } 
     86     }
     87     scanf("%d",&x);
     88     for(int i=1;i<=n;i++){
     89         nwa=nwb=0;
     90         query(i,x,nwa,nwb);
     91         if(nwb&&(ans==-1||aa*nwb>bb*nwa)){
     92             aa=nwa;
     93             bb=nwb;
     94             ans=i;
     95         }
     96     }
     97     printf("%d
    ",ans);
     98     scanf("%d",&m);
     99     for(int i=1;i<=m;i++){
    100         scanf("%d%d",&_s,&x);
    101         nwa=nwb=0;
    102         query(_s,x,nwa,nwb);
    103         printf("%lld %lld
    ",nwa,nwb);
    104     }
    105     return 0;
    106 }

    D2T1 同余方程

    题面

    怎么出模板题啊。。。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 using namespace std;
     6 typedef long long ll;
     7 ll a,b;
     8 ll exgcd(ll a,ll b,ll &d,ll &x,ll &y){
     9     if(!b){
    10         d=a;
    11         x=1;
    12         y=0;
    13     }else{
    14         exgcd(b,a%b,d,y,x);
    15         y-=x*(a/b);
    16     }
    17 }
    18 ll getinv(int a,int p){
    19     ll d,x,y;
    20     exgcd(a,p,d,x,y);
    21     return (x+p)%p;
    22 }
    23 int main(){
    24     scanf("%lld%lld",&a,&b);
    25     printf("%lld",getinv(a,b));
    26     return 0;
    27 }

    D2T2 借教室

    题面

    感觉比D1T2简单?一眼秒出线段树$O(nlogn)$做法,但是题目数据范围$n$和$m$都是$10^6$,吓得我以为有$O(n)$做法。。。又想了五分钟想出了差分+二分答案的做法,但时间复杂度还是$O(nlogm)$的,感觉不会有更好的做法,于是就码了一个,于是就过了。。。

    对于每个订单打标记加到差分数组里,然后二分答案即可。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 using namespace std;
     6 typedef long long ll;
     7 int n,m,L,R,d[1000001],s[1000001],t[1000001];
     8 ll pre,r[1000001],nw[1000001];
     9 bool ok=true;
    10 bool check(int k){
    11     for(int i=1;i<=n;i++)nw[i]=0;
    12     pre=0;
    13     for(int i=1;i<=k;i++){
    14         nw[s[i]]+=d[i];
    15         nw[t[i]+1]-=d[i];
    16     }
    17     for(int i=1;i<=n;i++){
    18         pre+=nw[i];
    19         if(pre>r[i])return false;
    20     }
    21     return true;
    22 }
    23 int main(){
    24     memset(nw,0,sizeof(nw));
    25     scanf("%d%d",&n,&m);
    26     for(int i=1;i<=n;i++){
    27         scanf("%lld",&r[i]);
    28     }
    29     for(int i=1;i<=m;i++){
    30         scanf("%d%d%d",&d[i],&s[i],&t[i]);
    31         nw[s[i]]+=d[i];
    32         nw[t[i]+1]-=d[i];
    33     }
    34     for(int i=1;i<=n;i++){
    35         pre+=nw[i];
    36         if(pre>r[i]){
    37             ok=false;
    38             break;    
    39         }
    40     }
    41     if(ok)return !puts("0");
    42     L=1,R=m;
    43     while(L<R){
    44         int mid=(L+R)/2;
    45         if(check(mid))L=mid+1;
    46         else R=mid;
    47     }
    48     printf("-1
    %d",L);
    49     return 0;
    50 }

    D2T3 疫情控制

    题面

    (看了题解)场上写了个60分$O(n^2logn)$的暴力,详细题解请看这篇博客

    总结:

    1.今天时间不充裕,没有严格按照noip时间来写题,随便做了做,三个小时干完两天的前两题之后就对着两道T3发呆,然而并没有搞出来,这样不能很好地模拟考场上的环境,以后要注意;

    2.简单题要尽量写快点,不要总是出弱智错,对节奏有很大影响;

    3.看到T3不要慌,实际上题解并不会用到很高级的算法(noip不考数据结构flag++),D1T3是个神秘倍增,D2T3大贪心,严格来说都不算很难,要仔细分析题目+熟练使用各种基础思想(二分,贪心等),放宽心态,不要让思想进入死胡同。

    4.SBLOJ!

  • 相关阅读:
    WPF学员管理系统
    dotnet-千星项目OpenAuthNet基于NetCore21的快速开发框架
    MVC5仓库管理系统
    华为设备IPC V200R002C0SPC SDK连接demo
    基础界面
    交通建设项目管理信息化系统
    Apache常见interview
    mamcached+(magent+keepalived高可用)搭建及理论概述
    TCP/IP三次挥手,四次断开(精简)
    简述FTP的主动模式与被动模式(精简)
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9860623.html
Copyright © 2011-2022 走看看