1. 程式人生 > >Day2下午解題報告

Day2下午解題報告

algo eve 數據 oid 素數表 eof ide bool struct

預計分數:100+100+30=230

實際分數:100+100+30=230
人品爆發&&智商爆發&&手感爆發

T3數據好水,,要是把數組開大一點的話還能多得10分,,,

T1洗澡

原題,不多說了。。

當時在北京花了接近一個小時才A..

技術分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const int MAXN=1e6;
 7 const
int INF=0x7ffff; 8 inline int read() 9 { 10 char c=getchar();int flag=1,x=0; 11 while(c<0||c>9) {if(c==-) flag=-1;c=getchar();} 12 while(c>=0&&c<=9) x=x*10+c-48,c=getchar();return x*flag; 13 } 14 char a[MAXN]; 15 int main() 16 { 17 //freopen("shower.in","r",stdin);
18 //freopen("shower.out","w",stdout); 19 scanf("%s",a+1); 20 int l=strlen(a+1); 21 int now=0,ans=0; 22 for(int i=1;i<=l;i++) 23 { 24 if(a[i]==() 25 { 26 if(now==l/2) ans++,now--;//修改 27 else now++; 28 } 29 else
30 { 31 if(now==0) ans++,now++; 32 else if(now<=l/2) now--; 33 } 34 } 35 printf("%d",ans+now/2); 36 return 0; 37 }
View Code

T2日記

一開始想到了70分的做法,寫著寫著就會100分的做法了。。

先打個素數表,

對於每次詢問的n

upperbound一個值,再在k-這個值之間二分,

技術分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define LL long long 
 7 using namespace std;
 8 const LL MAXN=1e6+10;
 9 const LL INF=0x7ffff;
10 inline LL read()
11 {
12     char c=getchar();LL flag=1,x=0;
13     while(c<0||c>9)    {if(c==-)    flag=-1;c=getchar();}
14     while(c>=0&&c<=9)     x=x*10+c-48,c=getchar();return x*flag;
15 }
16 LL T;
17 LL vis[MAXN];
18 LL prime[MAXN];
19 LL sprime[MAXN];
20 LL tot=0;
21 LL check(LL mid,LL n,LL k)
22 {
23     if(sprime[mid]-sprime[mid-k]<=n)    return 1;
24     else                             return 0;
25 }
26 int main()
27 {
28 //    freopen("diary.in","r",stdin);
29 //    freopen("diary.out","w",stdout);
30     for(LL i=2;i<=sqrt(1e6);i++)
31     {
32         if(vis[i]==0)
33             for(LL j=i*i;j<=1e6;j+=i)
34                 vis[j]=1;
35     }
36     for(LL i=2;i<=1e6;i++)    if(vis[i]==0)    
37         prime[++tot]=i;
38     //for(LL i=1;i<=tot;i++)
39     //    printf("%d\n",prime[i]);
40     T=read();
41     for(LL i=1;i<=tot;i++)
42         sprime[i]=sprime[i-1]+prime[i];
43     while(T--)
44     {
45         LL n=read(),k=read();
46         LL pos=upper_bound(prime+1,prime+tot+1,n)-prime;pos--;
47         LL ans=0;
48         bool flag=0;
49         LL l=k,r=pos;
50         while(l<=r)
51         {
52             LL mid=l+r>>1;
53             if(check(mid,n,k))    flag=1,ans=mid,l=mid+1;
54             else r=mid-1;
55         }
56         LL out=sprime[ans]-sprime[ans-k];
57         if(flag==1)    printf("%lld\n",out);
58         else         printf("-1\n");
59     }
60     return 0;
61 }
View Code

T3洗衣

直覺告訴我,這題一定非常難,,

因為我連暴力都不會打,

想了幾分鐘,感覺30分可以做,就是比較奇葩,,,需要存2^m棵樹,

代碼很惡心,,不過還好沒敲炸

技術分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<queue>
 6 
 7 using namespace std;
 8 const int MAXN=1001;
 9 const int INF=0x7ffff;
10 const int mod=1e9+7;
11 inline int read()
12 {
13     char c=getchar();int flag=1,x=0;
14     while(c<0||c>9)    {if(c==-)    flag=-1;c=getchar();}
15     while(c>=0&&c<=9)     x=x*10+c-48,c=getchar();return x*flag;
16 }
17 struct TREE
18 {
19     struct node
20     {
21         int u,v,w,nxt;
22     }edge[MAXN];
23     int head[MAXN];
24     int num;
25     int siz;//樹的大小 
26     int bg;//第一個節點的編號 
27     TREE()
28     {
29         memset(head,-1,sizeof(head));
30         num=1;siz=1;bg=1;
31     }
32     void add_edge(int x,int y,int z)
33     {
34         edge[num].u=x;
35         edge[num].v=y;
36         edge[num].w=z;
37         edge[num].nxt=head[x];
38         head[x]=num++;
39     }
40 }tree[MAXN];
41 int treenum=0;
42 inline void merge(int t1,int n1,int t2,int n2,int val)
43 {
44     treenum++;
45     for(int i=1;i<=tree[t1].num-1;i++)
46         tree[treenum].add_edge(tree[t1].edge[i].u,tree[t1].edge[i].v,tree[t1].edge[i].w);
47     for(int i=1;i<=tree[t2].num-1;i++)
48         tree[treenum].add_edge(tree[t2].edge[i].u+tree[t1].siz,tree[t2].edge[i].v+tree[t1].siz,tree[t2].edge[i].w);
49     tree[treenum].add_edge(n1,n2+tree[t1].siz,val);
50     tree[treenum].add_edge(n2+tree[t1].siz,n1,val);
51     tree[treenum].siz=tree[t1].siz+tree[t2].siz;
52 }
53 int dis[MAXN];
54 int vis[MAXN];
55 int ans=0;
56 inline void BFS()
57 {
58     for(int k=0;k<=tree[treenum].siz-1;k++)
59     {
60         memset(dis,0,sizeof(dis));
61         memset(vis,0,sizeof(vis));
62         dis[k]=0;
63         queue<int>q;
64         q.push(k);
65         while(q.size()!=0)
66         {
67             int p=q.front();
68             q.pop();
69             for(int i=tree[treenum].head[p];i!=-1;i=tree[treenum].edge[i].nxt)
70                 if(vis[tree[treenum].edge[i].v]==0)
71                     vis[tree[treenum].edge[i].v]=1,
72                     dis[tree[treenum].edge[i].v]=(dis[p]+tree[treenum].edge[i].w)%mod,
73                     q.push(tree[treenum].edge[i].v);
74         }
75         for(int i=k+1;i<=tree[treenum].siz-1;i++)
76             ans=(ans+dis[i])%mod;
77     }
78 }
79 int main()
80 {
81 //    freopen("cloth.in","r",stdin);
82 //    freopen("cloth.out","w",stdout);
83     int n=read();
84     for(int i=1;i<=n;i++)
85     {
86         int a=read(),b=read(),c=read(),d=read(),e=read();
87         merge(a,c,b,d,e);
88         ans=0;
89         BFS();
90         printf("%d\n",ans);
91     }
92     return 0;
93 }
40分暴力

100分

考慮每一棵樹的組成

一棵樹的答案一定包含了左邊的樹的答案

$f[i]=f[j]+f[k]+dis[new]$

考慮如何計算$dis[new]$

dis[i]=原來的j+新加的(左邊樹的大小*右邊樹的大小)+原來的k

原來的j=siz[j]*所有點到p1點的距離

$k=siz[k]+g[k][p2]$//g在第k棵樹中所有點到達p的距離

考慮如何求g

dp

設i是由j,k合並而來

$g[i][p]=g[j][p]+L+dis[j][p][p1]*siz[k]+g[k][p2]$

——》會T會boom——》開map做記憶化搜索

dis[j][p][p3]+l+dis[k][p2][p4]記憶化搜索

總結:

這次考的好是有諸多方面的原因的。。

T1原題,T2不難,T3正解非常難,暴力需要較強的代碼能力

這一套題貌似就是為我量身定做的啊233333

Day2下午解題報告