1. 程式人生 > 實用技巧 >week3做題記錄

week3做題記錄

A棧,純模擬。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 char s1[200000],s2[200000];
 7 int sta[200000],ans[200000];
 8 int main()
 9 {
10     int n,len=0;
11     while (~scanf("%d ",&n))
12     {
13         for (int i=1;i<=len;i++) sta[i]=0
; 14 scanf("%[^ ]",s1+1); 15 scanf("%s",s2+1); 16 int i=1,j=1,p=0,len=0; 17 while (i<=n||j<=n) 18 { 19 while (sta[len]!=s2[j]-'0'&&i<=n) 20 { 21 p++; 22 ans[p]=1; 23 len++; 24
sta[len]=s1[i]-'0'; 25 i++; 26 } 27 if (sta[len]!=s2[j]-'0') break; 28 p++; 29 ans[p]=0; 30 len--; 31 j++; 32 } 33 if (p==2*n) 34 { 35 printf("Yes.\n"); 36 for
(int i=1;i<=p;i++) if (ans[i]) printf("in\n");else printf("out\n"); 37 }else printf("No.\n"); 38 printf("FINISH\n"); 39 } 40 }

B連結串列,純模擬。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int pre[100000],nex[100000];
 7 int main()
 8 {
 9     int n;
10     scanf("%d",&n);
11     while (n)
12     {
13         n--;
14         int m;
15         scanf("%d",&m);
16         for (int i=1;i<m;i++) nex[i]=i+1;
17         for (int i=2;i<=m;i++) pre[i]=i-1;
18         nex[m]=0;
19         int head=1,w=1;
20         while (m>3)
21         {
22             if (w)
23             {
24                 for (int i=head,j=1;i;j++,i=nex[i]) if (j%2==0)
25                 {
26                     pre[nex[i]]=pre[i];
27                     nex[pre[i]]=nex[i];
28                     m--;
29                     //if (m<=3) break;
30                 }
31                 w=1-w;
32             }else
33             {
34                 for (int i=head,j=1;i;j++,i=nex[i]) if (j%3==0)
35                 {
36                     pre[nex[i]]=pre[i];
37                     nex[pre[i]]=nex[i];
38                     m--;
39                     //if (m<=3) break;
40                 }
41                 w=1-w;
42             }
43         }
44         for (int i=head;i;i=nex[i]) if (nex[i]==0) printf("%d",i);else printf("%d ",i);
45         printf("\n");
46     }
47 }

C棧,寫計算器,這裡用棧處理,加號和減號忽略,先計算乘法和除法,最後在遍歷一遍棧即可。

程式碼寫差了,其實可以寫得更簡短。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int main()
 7 {
 8     char s[500],sta[1000];
 9     double ss[1000];
10     while (~scanf("%[^\n]",s+1))
11     {
12         scanf("\n");
13         if (strlen(s+1)==1&&s[1]=='0') break;
14         int n=strlen(s+1),len=0;
15         s[n+1]=' ';
16         n++;
17         int last=1;
18         for (int i=1;i<=n;i++)
19         {
20             if (s[i]==' ')
21             {
22                 if (i-last==1)
23                 {
24                     if (s[i-1]=='+'||s[i-1]=='-'||s[i-1]=='*'||s[i-1]=='/')
25                     {
26                         len++;
27                         sta[len]=s[i-1];
28                     }else
29                     {
30                         if (sta[len]=='*')
31                         {
32                             len--;
33                             ss[len]=ss[len]*(double)(s[i-1]-'0');
34                         }else if (sta[len]=='/')
35                         {
36                             len--;
37                             ss[len]=ss[len]/(double)(s[i-1]-'0');
38                         }else
39                         {
40                             len++;
41                             sta[len]='&';
42                             ss[len]=(double)(s[i-1]-'0');
43                         }
44                     }
45                 }else
46                 {
47 
48                     double py=0;
49                     for (int j=last;j<i;j++) py=py*10.00+(double)(s[j]-'0');
50                     if (sta[len]=='*')
51                     {
52                         len--;
53                         ss[len]=ss[len]*(double)py;
54                     }else if (sta[len]=='/')
55                     {
56                         len--;
57                         ss[len]=ss[len]/(double)py;
58                     }else
59                     {
60                         len++;
61                         sta[len]='&';
62                         ss[len]=(double)py;
63                     }
64                 }
65                 last=i+1;
66             }
67         }
68         double ans=ss[1];
69         for (int i=3;i<=len;i++)
70         {
71             if (sta[i]=='&')
72             {
73                 if (sta[i-1]=='+') ans=ans+ss[i];else ans=ans-ss[i];
74             }
75         }
76         printf("%.2lf\n",ans);
77     }
78 }

D棧,實際上並沒有用到棧或者佇列就解決了問題。

其實可以發現一些簡單的數學規律,因此得到了一個O(n)的做法。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 char s[10000],s1[10000];
 7 int a[1000],b[1000],c[1000],py[1000],se[1000];
 8 int main()
 9 {
10     int n,tt=0;
11     while (1)
12     {
13         tt++;
14         scanf("%d",&n);
15         if (!n) break;
16         scanf("%s",s+1);
17         scanf("%s",s1+1);
18         int l=0,r=0;
19         for (int i=1;i<n-1;i++) if (s1[i]=='R') r++;else l++;
20         int j=r+1;
21         if (r%2==0)
22         {
23             for (int i=n-r;i<=n;i=i+2,j--) a[j]=i;
24             for (int i=n-1;j;j--,i=i-2) a[j]=i;
25         }else
26         {
27             for (int i=n-r;i<=n;i=i+2,j--) a[j]=i;
28             for (int i=n;j;j--,i=i-2) a[j]=i;
29         }
30         //l++;
31         if (l&1)
32         {
33             int j=1;
34             for (int i=l;i>=1;i=i-2,j++) b[j]=i;
35             for (int i=2;j<=l+1;j++,i=i+2) b[j]=i;
36         }else
37         {
38             int j=1;
39             for (int i=l;i>=2;i=i-2,j++) b[j]=i;
40             for (int i=1;j<=l+1;j++,i=i+2) b[j]=i;
41         }
42         if (s1[n-1]=='R')
43         {
44             int j=1;
45             for (int i=r+1;i>=1;i--,j++) c[j]=a[i];
46             for (int i=1;i<=l+1;i++,j++) c[j]=b[i];
47             //r++;
48         }else
49         {
50             int j=1;
51             for (int i=l+1;i>=1;i--,j++) c[j]=b[i];
52             for (int i=1;i<=r+1;i++,j++) c[j]=a[i];
53             //l++;
54         }
55         for (int i=1;i<=l+1;i++)
56         {
57             if (l%2==0)
58             {
59                 if (i&1) py[i]=0;else py[i]=1;
60             }else
61             {
62                 if (i&1) py[i]=1;else py[i]=0;
63             }
64         }
65         for (int i=n,j=1;i>=n-r;i--,j++)
66         {
67             if (r%2==0)
68             {
69                 if (j&1) py[i]=0;else py[i]=1;
70             }else
71             {
72                 if (j&1) py[i]=1;else py[i]=0;
73             }
74         }
75         if (s1[n-1]=='R') for (int i=n;i>=n-r;i--) py[i]=1-py[i];
76         else for (int i=1;i<=l+1;i++) py[i]=1-py[i];
77         for (int i=1;i<=n;i++) if (s[i]=='U') se[i]=1;else se[i]=0;
78         for (int i=1;i<=n;i++) if (py[i]) se[i]=1-se[i];
79         int m;
80         scanf("%d",&m);
81         printf("Pile %d\n",tt);
82         for (int i=1;i<=m;i++)
83         {
84             int x;
85             scanf("%d",&x);
86             printf("Card %d is a face",x);
87             if (se[c[x]]) printf(" up %d.\n",c[x]);
88             else printf(" down %d.\n",c[x]);
89         }
90     }
91 }

E佇列。實際上是佇列中的佇列...一開始看錯資料範圍,以為能暴力,後來加了一點點小小的優化。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e6+10;
int pre[N],nex[N],v[N],vv[N],cc[N];
int main()
{
    //freopen("test.in","r",stdin);
    int n,tt=0;
    while (1)
    {
        scanf("%d",&n);
        if (!n) break;
        printf("Scenario #%d\n",++tt);
        for (int i=1;i<=n;i++)
        {
            int m;
            scanf("%d",&m);
            for (int j=1;j<=m;j++)
            {
                int x;
                scanf("%d",&x);
                v[x]=i;
            }
        }
        for (int i=1;i<=n;i++) vv[i]=-1,cc[i]=0;
        scanf("\n");
        char s[10000];
        int he=0,ta=0;
        while (1)
        {
            scanf("%[^\n]",s+1);
            scanf("\n");
            if (s[1]=='S')
            {
                printf("\n");
                break;
            }
            int le=strlen(s+1);
            int w=0;
            for (int i=1;i<=le;i++) if (s[i]>='0'&&s[i]<='9') w=w*10+s[i]-'0';
            if (s[1]=='E')
            {
                if (!he)
                {
                    he=w;
                    ta=w;
                    pre[he]=0;
                    nex[he]=0;
                    vv[v[w]]=he;
                    cc[v[w]]=1;
                }else
                {
                    int last=vv[v[w]];
                    //for (int i=he;i;i=nex[i]) if (v[i]==v[w]) last=i;
                    if (last==-1||last==ta) nex[ta]=w,pre[w]=ta,ta=w,nex[w]=0;else pre[nex[last]]=w,nex[w]=nex[last],nex[last]=w,pre[w]=last;
                    vv[v[w]]=w;
                    cc[v[w]]++;
                }
            }else
            {
                printf("%d\n",he);
                cc[v[he]]--;
                if (!cc[v[he]]) vv[v[he]]=-1;
                he=nex[he];
                pre[he]=0;
            }
        }
    }
}

F,單調佇列裸題,只不過需要預處理時間。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 int f[15];
 7 int d[200000],q[200000],vp[200000];
 8 int pd(int x)
 9 {
10     if ((x%4==0&&x%400!=0)||x%100==0) return 1;
11     return 0;
12 }
13 int main()
14 {
15     //freopen("test.in","r",stdin);
16     int n,m;
17     f[1]=31;f[2]=28;f[3]=31;f[4]=30;f[5]=31;f[6]=30;f[7]=31;
18     f[8]=31;f[9]=30;f[10]=31;f[11]=30;f[12]=31;
19     while (1)
20     {
21         scanf("%d%d",&n,&m);
22         if (!n&&!m) break;
23         for (int i=1;i<=m;i++) vp[i]=0;
24         for (int i=1;i<=n;i++)
25         {
26             char s[5];
27             scanf("%s",s+1);
28             int y;
29             if (s[1]=='J'&&s[2]=='a') y=1;
30             if (s[1]=='F') y=2;
31             if (s[1]=='M'&&s[3]=='r') y=3;
32             if (s[1]=='A'&&s[3]=='r') y=4;
33             if (s[1]=='M'&&s[3]=='y') y=5;
34             if (s[1]=='J'&&s[3]=='n'&&s[2]=='u') y=6;
35             if (s[1]=='J'&&s[3]=='l') y=7;
36             if (s[1]=='A'&&s[2]=='u') y=8;
37             if (s[1]=='S') y=9;
38             if (s[1]=='O') y=10;
39             if (s[1]=='N') y=11;
40             if (s[1]=='D') y=12;
41             int t,nn,xs,x;
42             scanf("%d%d%d%d",&t,&nn,&xs,&x);
43             int tmp=xs+1;
44             tmp=tmp+(t-1)*24;
45             for (int j=y-1;j>=1;j--) if (j==2&&pd(nn)) tmp=tmp+29*24;else tmp=tmp+24*f[j];
46             for (int j=2000;j<nn;j++) if (pd(j)) tmp=tmp+366*24;else tmp=tmp+365*24;
47             vp[tmp]+=x;
48         }
49         long long ans=0;
50         int he=1,ta=0;
51         int ss,tt;
52         scanf("%d%d",&tt,&ss);
53         for (int i=1;i<=m;i++)
54         {
55             int x;
56             scanf("%d",&x);
57             while (ta>=he&&d[ta]-q[ta]*ss>=x-i*ss) ta--;
58             ta++;
59             d[ta]=x;
60             q[ta]=i;
61             while (q[ta]-q[he]>tt) he++;
62             if (vp[i]) ans=ans+1ll*d[he]*vp[i]+1ll*(i-q[he])*ss*vp[i];
63         }
64         printf("%I64d\n",ans);
65     }
66 }

G單調佇列裸題+1,只不過我寫了O(nlogn)的二分+rmq,感覺這個方法細節少一點(?),畢竟不是很擅長寫單調佇列。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=1e5+10;
 7 int e[N],a[N][20],n;
 8 int query(int l,int r)
 9 {
10     int lg=e[r-l+1];
11     return min(a[l][lg],a[r-(1<<lg)+1][lg]);
12 }
13 int efl(int x)
14 {
15     int l=1,r=x;
16     int ret=x;
17     while (l<=r)
18     {
19         int mid=l+r>>1;
20         if (query(mid,x)>=a[x][0])
21         {
22             ret=mid;
23             r=mid-1;
24         }else l=mid+1;
25     }
26     return ret;
27 }
28 int efr(int x)
29 {
30     int l=x,r=n;
31     int ret=x;
32     while (l<=r)
33     {
34         int mid=l+r>>1;
35         if (query(x,mid)>=a[x][0])
36         {
37             ret=mid;
38             l=mid+1;
39         }else r=mid-1;
40     }
41     return ret;
42 }
43 int main()
44 {
45     for (int i=2;i<=100000;i++) e[i]=e[i>>1]+1;
46     while (1)
47     {
48         scanf("%d",&n);
49         if (!n) break;
50         for (int i=1;i<=n;i++) scanf("%d",&a[i][0]);
51         for (int j=1;j<=17;j++) for (int i=1;i+(1<<j)-1<=n;i++) a[i][j]=min(a[i][j-1],a[i+(1<<j-1)][j-1]);
52         long long ans=0;
53         for (int i=1;i<=n;i++)
54         {
55             int x=efl(i),y=efr(i);
56             ans=max(ans,1ll*(y-x+1)*a[i][0]);
57         }
58         printf("%lld\n",ans);
59     }
60 }

H最大權閉合子圖,用網路流解決。

建圖是這樣的,正權點與源點連流量為權值的邊,負權點與源點連流量為絕對值的邊,如果x有指向y的邊,那麼y向x連無限流量的邊。

答案就是原來正權和減去最大流。

跑完網路流之後,可以得到一個最小割。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int inf=0x3f3f3f3f;
 7 const int N=1e6+10;
 8 int tot=1,cur[N],he[N],t[N],cc[N],ne[N],cnt[N],d[N],n;
 9 void link(int x,int y,int z)
10 {
11     tot++;
12     ne[tot]=he[x];
13     he[x]=tot;
14     t[tot]=y;
15     cc[tot]=z;
16     tot++;
17     ne[tot]=he[y];
18     he[y]=tot;
19     t[tot]=x;
20     cc[tot]=0;
21 }
22 int flow(int x,int y)
23 {
24     if (x==n+2) return y;
25     int cost=0,i=cur[x];
26     while (i)
27     {
28         cur[x]=i;
29         if (cc[i]&&d[t[i]]+1==d[x])
30         {
31             int ret=flow(t[i],min(y-cost,cc[i]));
32             cost=cost+ret;
33             cc[i]=cc[i]-ret;
34             cc[i^1]=cc[i^1]+ret;
35             if (y==cost||d[n+1]>n+2) return cost;
36         }
37         i=ne[i];
38     }
39     cur[x]=he[x];
40     if (cnt[d[x]]==1) d[n+1]=n+3;
41     cnt[d[x]]--;
42     cnt[d[x]+1]++;
43     d[x]++;
44     return cost;
45 }
46 int main()
47 {
48     int m;
49     while (~scanf("%d%d",&n,&m))
50     {
51         long long tmp=0;
52         for (int i=1;i<=n;i++)
53         {
54             int x;
55             scanf("%d",&x);
56             if (x>=0) tmp=tmp+x,link(n+1,i,x);else link(i,n+2,-x);
57         }
58         for (int i=1;i<=m;i++)
59         {
60             int x,y;
61             scanf("%d%d",&x,&y);
62             link(x,y,inf);
63         }
64         cnt[0]=n+2;
65         while (d[n+1]<=n+2) tmp=tmp-flow(n+1,inf);
66         printf("%I64d\n",tmp);
67         for (int i=1;i<=n+2;i++) he[i]=0,d[i]=0,cur[i]=0;
68         tot=1;
69     }
70 }