[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\times l_i}{r_{i+1}})$

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

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

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

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

所以以$l_i\times 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\n",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\n",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\n%d",L);
49     return 0;
50 }

D2T3 疫情控制

题面

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

总结:

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

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

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

4.SBLOJ!

posted @ 2018-10-27 11:34  DCDCBigBig  阅读(181)  评论(0编辑  收藏  举报