zoukankan      html  css  js  c++  java
  • 杂题选录

    LuoguP3948数据结构 10-20

    是比较裸的差分题目,但是要注意在线查询的时候开始傻了,每次都暴力地从1到n搞一遍,还存在数组中每次都要清空...结果T了很多点。

    其实在线查询的时候直接用变量+扫到r就行了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 
     5 using namespace std;
     6 typedef long long ll;
     7 
     8 int n,opt,tot,fin;
     9 char doit[5];
    10 ll sjt,minn,maxx;
    11 ll cha[100000],sta[100000],sum[100000];
    12 
    13 int main()
    14 {
    15     scanf("%d%d",&n,&opt);
    16     scanf("%lld%lld%lld",&sjt,&minn,&maxx);
    17     for(int i=1;i<=opt;i++)
    18     {
    19         int l=0,r=0;ll x=0;
    20         scanf("%s",doit+1);
    21         if(doit[1]=='A')
    22         {
    23             scanf("%d%d%lld",&l,&r,&x);
    24             cha[l]+=x,cha[r+1]-=x;
    25         }
    26         else
    27         {
    28             scanf("%d%d",&l,&r);
    29             ll noww=0,cnt=0;
    30             for(int i=1;i<=r;i++)
    31             {
    32                 noww+=cha[i];
    33                 ll cmp=noww*i%sjt;
    34                 if(i>=l&&cmp>=minn&&cmp<=maxx) cnt++;
    35             }
    36             printf("%lld
    ",cnt);
    37         }
    38     }
    39     for(int i=1;i<=n;i++) sta[i]=sta[i-1]+cha[i];
    40     for(int i=1;i<=n;i++)
    41     {
    42         sum[i]=sum[i-1];
    43         ll cmp=sta[i]*i%sjt;
    44         if(cmp>=minn&&cmp<=maxx) sum[i]++;
    45     }
    46     scanf("%d",&fin);
    47     for(int i=1;i<=fin;i++)
    48     {
    49         int l=0,r=0;
    50         scanf("%d%d",&l,&r);
    51         printf("%lld
    ",sum[r]-sum[l-1]);
    52     }
    53     return 0;
    54 }
    View Code

    sjtu1329 聚餐 10-20

    二进制枚举裸题。从数据范围中就可以看出,结果卡了半个小时多...因为单词拼错了....sigh拼成sign...我真傻,真的。

    另外注意因为二进制数位从0开始记起,所以要对于菜肴号要减1.

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4  
     5 using namespace std;
     6  
     7 int T,n,m,fake,ans;
     8 char sss; 
     9 int request[100][100],num[100];
    10  
    11 inline int read(){
    12     char ch=getchar();int x=0,f=1;
    13     while(ch<'0' || ch>'9') {
    14        if(ch=='-') f=-1;
    15           ch=getchar();
    16     }
    17     while(ch<='9' && ch>='0') {
    18        x=x*10+ch-'0';  
    19        ch=getchar();
    20     }
    21     sss=ch;
    22     return x*f;
    23 }
    24  
    25 int main()
    26 {
    27     scanf("%d",&T);
    28     while(T--)
    29     {
    30         scanf("%d%d",&n,&m);
    31         for(int i=1;i<=m;i++)
    32             for(int j=1;j<=n;j++)
    33             {
    34                 num[i]++;
    35                 request[i][j]=read();
    36                 if(sss!=' ') break;
    37             }
    38         fake=(1<<n)-1;
    39         for(int i=0;i<=fake;i++)
    40         {
    41             int cnt=0;
    42             for(int j=1;j<=m;j++)
    43                 for(int k=1;k<=num[j];k++)
    44                 {
    45                     if(request[j][k]<0)
    46                     {
    47                         int tmp=-request[j][k]-1;
    48                         if(!((i>>tmp)&1)) {cnt++;break;} 
    49                     }
    50                     else
    51                     {
    52                         int tmp=request[j][k]-1;
    53                         if((i>>tmp)&1) {cnt++;break;}
    54                     }
    55                 }
    56             ans=max(ans,cnt);
    57         }
    58         if(ans==m) printf("Bingo!
    ");
    59         else printf("Sigh...
    ");
    60         ans=0;
    61         memset(num,0,sizeof(num));
    62     }
    63     return 0;
    64 }
    View Code

    chengni邀请赛 我宋金涛天下第一 10-21

    看到这个函数的启发,我首先想的是前几天正睿的分层图最短路,三次迭代之后会回到原来的值。于是手推了下几个随机的小奇数/偶数。发现最后都会变成1。于是就又想到线段树维护区间开方那题,可能这道题也是不是连续搞几次就过了呢...然后就写了...然后自己出了数据开始对拍大样例。发现锅了...发现修改的时候写成区间了,写成单点即可。

    不过当然是托了数据随机的福,不然会T死啊

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define maxn 200090
     4 
     5 using namespace std;
     6 typedef long long ll;
     7 
     8 int n,m;
     9 ll seq[maxn];
    10 struct SegmentTree{
    11     int l,r;
    12     ll sum,val;
    13 }t[maxn*4];
    14 
    15 ll f(ll x)
    16 {
    17     if(x==1) return 1;
    18     if(x&1) return 3*x+1;
    19     return x>>1;
    20 }
    21 
    22 void build(int p,int l,int r)
    23 {
    24     t[p].l=l,t[p].r=r;
    25     if(l==r)
    26     {
    27         t[p].val=t[p].sum=seq[l];
    28         return ;
    29     }
    30     int mid=(l+r)>>1;
    31     build(p*2,l,mid);
    32     build(p*2+1,mid+1,r);
    33     t[p].sum=t[p*2].sum+t[p*2+1].sum;
    34     t[p].val=max(t[p*2].val,t[p*2+1].val);
    35 }
    36 
    37 void change(int p,int l,int r)
    38 {
    39     if(t[p].l==t[p].r)
    40     {
    41         t[p].val=f(t[p].val);
    42         t[p].sum=f(t[p].sum);
    43         return ;
    44     }
    45     int mid=(t[p].l+t[p].r)>>1;
    46     if(l<=mid&&t[p*2].val>1) change(p*2,l,r);
    47     if(r>mid&&t[p*2+1].val>1) change(p*2+1,l,r);
    48     t[p].sum=t[p*2].sum+t[p*2+1].sum;
    49     t[p].val=max(t[p*2].val,t[p*2+1].val);
    50 }
    51 
    52 ll ask(int p,int l,int r)
    53 {
    54     if(t[p].l==l&&t[p].r==r) return t[p].sum;
    55     int mid=(t[p].l+t[p].r)>>1;
    56     if(l>mid) return ask(p*2+1,l,r);
    57     else if(r<=mid) return ask(p*2,l,r);
    58     else return ask(p*2,l,mid)+ask(p*2+1,mid+1,r);
    59 }
    60 
    61 int main()
    62 {
    63 
    64     scanf("%d%d",&n,&m);
    65     for(int i=1;i<=n;i++) scanf("%lld",&seq[i]);
    66     build(1,1,n);
    67     while(m--)
    68     {
    69         int op=0,l=0,r=0;
    70         scanf("%d%d%d",&op,&l,&r);
    71         if(op==1) change(1,l,r);
    72         else if(op==2) printf("%lld
    ",ask(1,l,r));
    73     }
    74     return 0;
    75 }
    View Code

    chengni邀请赛 我再也不划水了 10-21

    模拟题啊QAQ。注意AKNOI/AKIOI等卡牌满足大于等于即可。而不苛刻地等于。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<iostream>
     4 
     5 using namespace std;
     6 
     7 int T;
     8 double ans;
     9 int tong[1000];
    10 char op[10];
    11 
    12 void add()
    13 {
    14     if(tong[0]>=1&&tong[10]>=1&&tong[8]>=2&&tong[14]>=1) {ans+=100;return ;}
    15     if(tong[0]==5||tong[10]==5||tong[13]==5||tong[14]==5||tong[8]==5||tong[15]==5) 
    16         {ans+=95;return ;}
    17     if(tong[0]>=1&&tong[10]>=1&&tong[13]>=1&&tong[14]>=1&&tong[8]>=1) {ans+=90;return ;}
    18     if(tong[8]>=2&&tong[14]>=1) {ans+=85;return ;}
    19     if(tong[8]>=1&&tong[13]>=1&&tong[14]>=1) {ans+=80;return ;}
    20     if(tong[13]>=1&&tong[14]>=1&&tong[8]>=1) {ans+=75;return ;}
    21     if(tong[0]>=1&&tong[10]>=1) {ans+=70;return ;}
    22     if(tong[0]==4||tong[10]==4||tong[13]==4||tong[14]==4||tong[8]==4||tong[15]==4)
    23         {ans+=60;return ;}
    24     if(tong[0]==3||tong[10]==3||tong[13]==3||tong[14]==3||tong[8]==3||tong[15]==3)
    25         {ans+=50;return ;}
    26     int pos=1,tmp=0;
    27     for(int i=1;i<=tong[0];i++) tmp+=pos*1,pos++;
    28     for(int i=1;i<=tong[8];i++) tmp+=pos*4,pos++;
    29     for(int i=1;i<=tong[10];i++) tmp+=pos*7,pos++;
    30     for(int i=1;i<=tong[13];i++) tmp+=pos*11,pos++;
    31     for(int i=1;i<=tong[14];i++) tmp+=pos*12,pos++;
    32     for(int i=1;i<=tong[15];i++) tmp+=pos*19,pos++;
    33     tmp%=27;
    34     ans+=tmp;
    35 }
    36 
    37 void A()
    38 {
    39     tong['A'-'A']++;add();tong['A'-'A']--;
    40 }
    41 
    42 void K()
    43 {
    44     tong['K'-'A']++;add();tong['K'-'A']--;
    45 }
    46 
    47 void N()
    48 {
    49     tong['N'-'A']++;add();tong['N'-'A']--;
    50 }
    51 
    52 void O()
    53 {
    54     tong['O'-'A']++;add();tong['O'-'A']--;    
    55 }
    56 
    57 void I()
    58 {
    59     tong['I'-'A']++;add();tong['I'-'A']--;
    60 }
    61 
    62 void P()
    63 {
    64     tong['P'-'A']++;add();tong['P'-'A']--;
    65 }
    66 
    67 int main()
    68 {
    69     scanf("%d",&T);
    70     while(T--)
    71     {
    72         scanf("%s",op+1);
    73         for(int i=1;i<=4;i++)
    74             tong[op[i]-'A']++;
    75         A();
    76         K();
    77         N();
    78         O();
    79         I();
    80         P();
    81         ans=ans/6;
    82         printf("%.3lf
    ",ans);
    83         ans=0;
    84         tong[0]=0,tong[10]=0,tong[13]=0,tong[14]=0,tong[8]=0,tong[15]=0;
    85     }
    86     return 0;
    87 }
    View Code

    CF484A Bits 10-22

    题目大意:求区间$[l,r]$中,二进制表示中1个数最多的区间内的数。

    贪心地从$l$开始一位位填,但是开始想的比较naive,先统计下$l$的位数,再把位数上所有的数都填成1.注意,这里都填成1后可能就会超过$r$了,这个贪心是错的。

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 typedef long long ll;
     6 
     7 int T;
     8 ll l,r;
     9 
    10 ll ksm(ll a,ll b)
    11 {
    12     ll tmp=1;
    13     while(b)
    14     {
    15         if(b&1) tmp=tmp*a;
    16         b>>=1;
    17         a=a*a;
    18     }
    19     return tmp;
    20 }
    21 
    22 int work(ll x)
    23 {
    24     int tot=0;
    25     ll tmp=x;
    26     while(tmp)
    27     {
    28         tmp/=2;
    29         tot++;
    30     }
    31     return tot;
    32 }
    33 
    34 int main()
    35 {
    36     scanf("%d",&T);
    37     while(T--)
    38     {
    39         scanf("%lld%lld",&l,&r);
    40         if(l==r){printf("%lld
    ",l);continue;}
    41         int cnt=work(l);
    42         ll begi=(1<<cnt)-1;
    43         while(1)
    44         {
    45             if(begi+ksm(2,cnt)>r) break;
    46             begi+=ksm(2,cnt);
    47             cnt++;
    48         }
    49         printf("%lld
    ",begi);
    50     }
    51     return 0;
    52 }
    错的

    但是还好整体方向是对的,即每一位从$l$开始尽量填1。这里我们可以用位运算(或运算)来帮忙。但是注意由于位运算优先级很低,所以我们需要大力加括号

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 typedef long long ll;
     6 
     7 int T;
     8 ll l,r;
     9 
    10 int main()
    11 {
    12     scanf("%d",&T);
    13     while(T--)
    14     {
    15         scanf("%lld%lld",&l,&r);
    16         if(l==r){printf("%lld
    ",l);continue;}
    17         for(ll i=1;(i|l)<=r;i<<=1) l|=i; 
    18         printf("%lld
    ",l);
    19     }
    20     return 0;
    21 }
    View Code

    sjtu 1621 未命名 10-21

    题目大意:给你一个01矩阵,你可以任意交换两行无限多次,求最大全白子矩形大小。

    这个思想在之前做的一道题中体现过。(玉蟾宫)

    一众Zhengrui学成而归的dalao表示这是他们做过一道类似的原题。只不过他们是可以交换任意两列无限多次。不过我们把地图翻转过来不就一样了嘛qwq。

    思路:设$f[i][j]$表示从$(i,j)$向上最多能延伸的高度(都是1的部分)。然后我们枚举每一行对同一行上的$f[i][j]$进行从小到大排序。(即任意交换两列),然后尝试向右向上扩展。因为是从小到大排序的,所以对于同一行上的$i<j$,$i$位置能延伸到的,$j$位置同样能延伸到。就可以从这里出发更新答案。

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 
     6 int n,ans;
     7 int f[1090][1090];
     8 char tmp[1090],last[1090][1090],mapp[1090][1090];
     9 
    10 int main()
    11 {
    12     scanf("%d",&n);
    13     for(int i=1;i<=n;i++)
    14     {
    15         scanf("%s",tmp+1);
    16         for(int j=1;j<=n;j++) last[i][j]=tmp[j];
    17     }
    18     for(int i=1;i<=n;i++)
    19     {
    20         for(int j=n;j>=1;j--)
    21             mapp[j][i]=last[i][n-j+1];
    22     }
    23     for(int i=1;i<=n;i++)
    24         for(int j=1;j<=n;j++)
    25             if(mapp[i][j]=='1') f[i][j]=f[i-1][j]+1; 
    26     for(int i=1;i<=n;i++)
    27     {
    28         sort(f[i]+1,f[i]+1+n);
    29         for(int j=1;j<=n;j++)
    30             ans=max(ans,f[i][j]*(n-j+1));
    31     }    
    32     printf("%d",ans);
    33     return 0;
    34 }
    View Code

    chengni给对面新生出的题 树链剖分

    题目大意:求出满足树链剖分要求的字典序最小的$dfs$序。

    思路:因为我们要满足树链剖分的性质,所以肯定先递归重儿子这是毋庸置疑的。那么字典序的大小差异只会产生在轻儿子中。表示被邻接表限制了想象力,我们可以用$vector$存边。然后对每个点的儿子vector集合排个序就好了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<vector>
     4 #define maxn 10090 
     5 
     6 using namespace std;
     7 
     8 int n,tot,cnt;
     9 int size[maxn],rk[maxn],son[maxn];
    10 vector<int>s[maxn];
    11 
    12 void dfs1(int u,int fa)
    13 {
    14     size[u]=1;
    15     for(int i=0;i<s[u].size();i++)
    16     {
    17         int v=s[u][i];
    18         if(v==fa) continue;
    19         dfs1(v,u);
    20         size[u]+=size[v];
    21         if(size[v]>size[son[u]]) son[u]=v;
    22     }
    23 }
    24 
    25 void dfs2(int u,int fa)
    26 {
    27     rk[++cnt]=u;
    28     if(!son[u]) return ;
    29     dfs2(son[u],u);
    30     for(int i=0;i<s[u].size();i++)
    31     {
    32         int v=s[u][i];
    33         if(fa==v||v==son[u]) continue;
    34         dfs2(v,u);
    35     }
    36 }
    37 
    38 int main()
    39 {
    40     scanf("%d",&n);
    41     for(int i=1;i<=n-1;i++)
    42     {
    43         int x=0,y=0;
    44         scanf("%d%d",&x,&y);
    45         s[x].push_back(y);
    46         s[y].push_back(x);
    47     }
    48     for(int i=1;i<=n;i++) sort(s[i].begin(),s[i].end());
    49     dfs1(1,0);
    50     dfs2(1,0);
    51     for(int i=1;i<=cnt;i++) printf("%d ",rk[i]);
    52     return 0;
    53 }
    View Code

    chengni给对面新生出的题 线段树

    题目大意:给你一个线段树和很多区间,求这个区间被多少个区间恰好表示。

    思路:吸取线段树中的思路:递归求解即可。但是写的有点慢啊...我还是太菜了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 
     6 int n,m;
     7 
     8 int ask(int l,int r,int posl,int posr)
     9 {    
    10     int mid=(l+r)>>1;
    11     if(l>=posl&&r<=posr) return 1;
    12     if(posl>mid) return ask(mid+1,r,posl,posr);
    13     else if(posr<=mid) return ask(l,mid,posl,posr);
    14     else return ask(l,mid,posl,posr)+ask(mid+1,r,posl,posr); 
    15 }
    16 
    17 int main()
    18 {
    19     scanf("%d%d",&n,&m);
    20     for(int i=1;i<=m;i++)
    21     {
    22         int l=0,r=0; 
    23         scanf("%d%d",&l,&r);
    24         printf("%d
    ",ask(1,n,l,r));
    25     }
    26     return 0;
    27 }
    View Code

    2018-10-21noi.ac邀请赛Day2 ball

    数轴上有 n 个球,每个球直径为 1,第 i 个球的左端点为 pi(即占据了数轴上 [pi,pi+1]。在 P位置有一堵墙。

    有q个操作,每次要么以x位置为左端点放一个新球(如果有了就不管),要么把最左边的球往右推。一个球碰到另一个的时候,旧球停下来,新球继续滚。球碰到墙的时候就停下来。

    最后你需要输出所有球的位置。

    手玩下样例可以发现,每次进行操作2后,每个球的位置会变成它之后的那个球的位置减1,于是便有了一个$O(n^2)$算法,每次都$O(n)$地更新一下序列,并用一个$vis$数组记录下这个位置有没有被占用。加元素的时候重新排遍序就行了。期望得分30分。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<map>
     4 
     5 using namespace std;
     6 
     7 int n,Q,wal,tot;
     8 int p[200090];
     9 map<int,int>vis;
    10 
    11 int main()
    12 {
    13     scanf("%d%d%d",&n,&Q,&wal);
    14     for(int i=1;i<=n;i++) scanf("%d",&p[i]),vis[p[i]]=1;
    15     p[n+1]=wal;tot=n+1;
    16     sort(p+1,p+1+n+1);
    17     if((n<=1000&&Q<=1000)||Q<n)
    18     {
    19         while(Q--)
    20         {
    21             int op=0,x=0;
    22             scanf("%d",&op);
    23             if(op==1)
    24             {
    25                 scanf("%d",&x);
    26                 if(vis[x]) continue;
    27                 p[++tot]=x;
    28                 sort(p+1,p+tot+1);
    29                 vis[x]=1;
    30             }
    31             else if(op==2)
    32             {
    33                 for(int i=1;i<=tot-1;i++)
    34                     vis[p[i]]=0,p[i]=p[i+1]-1,vis[p[i]]=1;
    35             }
    36         }
    37         for(int i=1;i<=tot-2;i++) printf("%d ",p[i]);
    38         printf("%d",p[tot-1]); 
    39         return 0;
    40     }
    41     if(Q>=n)
    42     {
    43         int bg=wal-n;
    44         for(int i=bg;i<=wal-2;i++) printf("%d ",i);
    45         printf("%d",wal-1);
    46         return 0;
    47     }
    48     return 0;
    49 }
    30

    其实一定快要想到正解了,但是没有往深处想:考虑操作2,球的数量是一定的,只是位置发生变化,于是每次推动的时候,是将每个球的位置-1,再把最左边的球放到$p-1$处。因此我们只需记-1的次数,再用set维护。set是可以一个元素不可重复、自动排序(类似优先队列)的集合,插入函数insert,如果元素已经存在则操作不进行;还有强大的erase操作。某些程度上可以代替迭代器。输出元素时要加*号解除引用。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<set>
     4 
     5 using namespace std;
     6 
     7 int n,q,p,k,x;
     8 set<int>S;
     9 
    10 int main()
    11 {
    12     scanf("%d%d%d",&n,&q,&p);
    13     for(int i=1;i<=n;i++) scanf("%d",&x),S.insert(x);
    14     while(q--)
    15     {
    16         int op=0;
    17         scanf("%d",&op);
    18         if(op==1) scanf("%d",&x),S.insert(k+x);
    19         else S.erase(S.begin()),S.insert(p+k),k++;
    20     }
    21     while(S.size())
    22         printf("%d ",*S.begin()-k),S.erase(S.begin());
    23     return 0;
    24 }
    AC

    ZROI Day14 字符串

    题目大意:给定一个长度为$n$的字符串,它的字典集为$M$。也就是说每一位有$M$种不同的字母可以选。对于这个字符串所有连续的长度为$k$的子串都必须是回文串,求有多少不同方案。

    其实是道数学题,我们分情况讨论。

    当$k>n$或$k=1$时,显然答案为$m^n$。因为这是不再有回文串的限制。

    当$k=n$时,不难想,设$qwq$=$(n+1)>>1$,那么答案为$m^{qwq}$。因为这时配对有$(n+1)>>1$组。这启发我们统计可能的对数。

    当$k<n$时,我们可以多画一下图,合并一定相等的位置。最后总结出当$k$为奇数,答案为$m^2$,因为只能有两对。当$k$为偶数,答案为$m$。因为所有字符都必须一样。

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 typedef long long ll;
     6 ll moder=1e9+7;
     7 
     8 ll n,m,k;
     9 
    10 ll ksm(ll a,ll b)
    11 {
    12     ll tmp=1;
    13     while(b)
    14     {
    15         if(b&1) tmp=tmp*a%moder;
    16         b>>=1;
    17         a=a*a%moder;
    18     }
    19     return tmp;
    20 }
    21 
    22 int main()
    23 {
    24     scanf("%lld%lld%lld",&n,&m,&k);
    25     if(k>n||k==1) {printf("%lld
    ",ksm(m,n)%moder);return 0;}
    26     if(k==n) {printf("%lld
    ",ksm(m,(n+1)>>1)%moder);return 0;}
    27     if(k&1) printf("%lld
    ",ksm(m,2));
    28     else printf("%lld
    ",m);
    29     return 0;
    30 }
    View Code

    牛客某比赛 小可爱序列

    题目大意:

    您需要维护一个长度为n的序列,小可爱只用了以下两种操作:

    a.将最后一个数挪到第一位
    b.将序列第3位挪到第一位
    你需要给出最后的序列。链接:https://ac.nowcoder.com/acm/contest/224/B
    对于所有数据
    4<=n<=2000
    m<=100000
    对于每次操作的操作数<=998244353

    又想到了那道《我宋全涛天下第一》,感觉这么大的操作数显然就是在唬人:对于a操作,只要操作膜3以后的次数即可;对于b操作同理,膜$n$以后的次数即可。具体实现我们两个双端队列即可。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<queue>
     4 
     5 using namespace std;
     6 
     7 int n,m,x,num;
     8 deque<int>q1,q2;
     9 int tmp[10];
    10 char op[10];
    11 
    12 void work1()
    13 {
    14     num%=3;
    15     //printf("%d
    ",num);
    16     for(int i=1;i<=num;i++)
    17         x=q1.back(),q1.pop_back(),q1.push_front(x);
    18     for(int i=1;i<=3;i++)
    19         tmp[i]=q1.front(),q1.pop_front(),q2.pop_front();
    20     for(int i=3;i>=1;i--)
    21         q1.push_front(tmp[i]),q2.push_front(tmp[i]);
    22 }
    23 
    24 void work2()
    25 {
    26     num%=n;
    27     //printf("%d
    ",num);
    28     for(int i=1;i<=num;i++)
    29         x=q2.back(),q2.pop_back(),q2.push_front(x);
    30     for(int i=1;i<=3;i++)
    31         tmp[i]=q2.front(),q2.pop_front();
    32     q1.clear();
    33     for(int i=3;i>=1;i--) q1.push_front(tmp[i]),q2.push_front(tmp[i]);
    34 }
    35 
    36 int main()
    37 {
    38     scanf("%d%d",&n,&m);
    39     for(int i=1;i<=3;i++) 
    40         scanf("%d",&x),q1.push_back(x),q2.push_back(x);
    41     for(int i=4;i<=n;i++)
    42         scanf("%d",&x),q2.push_back(x);
    43     for(int i=1;i<=m;i++)
    44     {
    45         scanf("%d",&num);
    46         scanf("%s",op+1);
    47         if(op[1]=='a') work2();
    48         else if(op[1]=='b') work1();
    49     //    for(int j=1;j<=n;j++)
    50     //        x=q2.front(),printf("%d ",x),q2.pop_front(),q2.push_back(x);
    51     //    printf("
    ");
    52     }
    53     for(int i=1;i<=n;i++)
    54         x=q2.front(),q2.pop_front(),printf("%d ",x); 
    55     return 0;
    56 }
    View Code

    LuoguP2338失败的滑雪

    其实是道大模拟==。但是码力不足需要练==。而且需要有一个清晰的思路,不能以距离为轴,因为每次走一秒加上速度的话,中间的时间可能还有失误,这是看不出来的:(错误代码)

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 
     6 int n,v=1,tot;
     7 char op[10];
     8 bool tim[10000090],dis[2000];
     9 
    10 int main()
    11 {
    12     scanf("%d",&n);
    13     for(int i=1;i<=n;i++)
    14     {
    15         int x=0;
    16         scanf("%s",op+1);
    17         scanf("%d",&x);
    18         if(op[1]=='T') tim[x]=1;
    19         else if(op[1]=='D') dis[x]=1;
    20     }
    21     for(int i=1;i<=1000;i++)
    22     {
    23         tot+=v;
    24         if(dis[i]) v++;
    25         if(tim[tot]) v++;
    26     }
    27     printf("%d
    ",tot);
    28     return 0;
    29 } 
    View Code

    正确做法:以失误为轴

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 
     6 int n,cntt,cntd;
     7 double pos,v=1,tot,tv;
     8 char op[10];
     9 int tim[20000],dis[20000];
    10 
    11 int main()
    12 {
    13     scanf("%d",&n);
    14     for(int i=1;i<=n;i++)
    15     {
    16         int x=0;
    17         scanf("%s",op+1);
    18         scanf("%d",&x);
    19         if(op[1]=='T') tim[++cntt]=x;
    20         else if(op[1]=='D') dis[++cntd]=x;
    21     }
    22     sort(tim+1,tim+1+cntt);tim[cntt+1]=1e9;
    23     sort(dis+1,dis+1+cntd);dis[cntd+1]=1e9;
    24     int i=1,j=1;
    25     while(i<=cntt||j<=cntd)
    26     {
    27         tv=1.0/v;
    28         double pos1=pos+tv*(tim[i]-tot);
    29         double pos2=dis[j];
    30         if(pos1<pos2)
    31         {
    32             pos=pos1;
    33             tot=tim[i];
    34             i++;v++;
    35         }
    36         else
    37         {
    38             tot+=(pos2-pos)/tv;
    39             pos=pos2;
    40             j++;v++;
    41         }
    42     }
    43     tv=1.0/v;
    44     tot+=(1000-pos)/tv;
    45     printf("%.0lf",tot);
    46     return 0;
    47 } 
    View Code

     以及四舍五入(double)的输出方式:”.0lf“。涨姿势了/cy。


    ZROI day16 道路规划

    题目大意:给你一个$n$个点的无向正权连通图,以及一个记录两点间最短路的矩阵,请问至少需要多少条边能满足这个矩阵。$n<=300$。

    两个点的最短路相连方式有两种:通过其他点松弛来的/两个点直接相连。

    考虑$floyd$算法,若$f[i][j]=f[i][k]+f[k][j]$,那么说明图中存在其他点使$i$与$j$有最短路,如果不能松弛,那么说明需要另在两个点间连边。计数就是这样计出来的。

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 
     6 int n,ans;
     7 int f[500][500],vis[500][500];
     8 
     9 int main()
    10 {
    11     scanf("%d",&n);
    12     for(int i=1;i<=n;i++)
    13         for(int j=1;j<=n;j++)
    14             scanf("%d",&f[i][j]);
    15     for(int k=1;k<=n;k++)
    16         for(int i=1;i<=n;i++)
    17             for(int j=1;j<=n;j++)
    18             {
    19                 if(i==k||j==k||i==j) continue;
    20                 if(f[i][j]==f[i][k]+f[k][j]) vis[i][j]=1;
    21             }
    22     for(int i=1;i<=n;i++)
    23         for(int j=i+1;j<=n;j++)
    24             if(!vis[i][j]) ans++;
    25     printf("%d
    ",ans);
    26     return 0;
    27 }

    在正睿参加的最后一场模拟赛  Standard T1 Problem

    开始给$f$函数打的表,企图发现一些规律,但是打了很久没看出来...后来手动搞了一个数试验一下,发现是各数位的平方和。例如$f(531)=5^2+3^2+1^2$。

    打表的时候发现其实能满足条件的数其实很少...不妨枚举$k$的倍数,那么计算的范围就会少很多。实际上最多只需要算18*81(9*9)。这是1e18的最大$f$值 。枚举的时候注意判断边界,以及列出的式子是否正确。(错了很多次)还有计算$f$函数的时候,其实正常算就好,考场上又晕了。

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 typedef long long ll;
     6 
     7 int T;
     8 ll k,l,r,ans;
     9 
    10 ll f(ll x)
    11 {
    12     ll F=0,tmp=x;
    13     while(tmp)
    14     {
    15         F+=(tmp%10)*(tmp%10);
    16         tmp/=10; 
    17     }
    18     return F;
    19 }
    20 
    21 int main()
    22 {
    23     scanf("%d",&T); 
    24     while(T--)
    25     {
    26         scanf("%lld%lld%lld",&k,&l,&r);    
    27         for(ll i=0;i<=81*18;i++)
    28         {
    29             if(i*k<l) continue;
    30             if(i*k>r) break;
    31             if(f(i*k)*k==i*k) ans++;
    32         }
    33         printf("%lld
    ",ans);
    34         ans=0;
    35     }
    36     return 0;
    37 }

    Permutation Problem

    如何拿40分的n<=17情况。当然是状压!!但是考场上只把全排列的部分分拿了。

    可以暴力dp,设$f[i]$表示放了的集合为$i$(即放了为1没放为0)时的方案数,可以做到$O(n*2^n)$转移。转移方程$f[i|(1<<j)]$+=$f[i]$。还要注意初值$f[0]=1$。

     1 #include<cstdio>
     2 #include<algorithm>
     3 
     4 using namespace std;
     5 typedef long long ll;
     6 ll moder=1e9+7;
     7 
     8 int n,k,fake;
     9 ll f[140000];
    10 
    11 int main()
    12 {
    13     scanf("%d%d",&n,&k);
    14     if(k==0) {printf("1");return 0;}
    15     fake=(1<<n)-1;
    16     f[0]=1;
    17     for(int i=0;i<=fake;i++)
    18     {
    19         int pos=1;
    20         for(int j=0;j<n;j++)
    21             if(i&(1<<j)) pos++;
    22         for(int j=0;j<n;j++)
    23         {
    24             if(i&(1<<j)) continue;
    25             if(abs(j+1-pos)>k) continue;
    26             f[i|(1<<j)]+=f[i];
    27             f[i|(1<<j)]%=moder;
    28         }
    29     }
    30     printf("%lld",f[fake]);
    31     return 0;
    32 }

    其实用状压搞部分分的情况也是不少。比如某次noi.ac测试,也出了一道类似排列的题,我们同样能用状压搞到不错的分数。原题是这样的

  • 相关阅读:
    创业者,你有梦想吗?
    中型企业能撑过现金危机
    共享经济与优步(Uber)如何获取监管支持?
    TJX:好买手养成记
    问得更少,获悉更多
    成功创新者该问的问题
    物联网革命的核心是“网”,而不是“物”
    成功领导力的10大关键
    人们抗拒组织变革的十大原因
    李彦宏:PC时代结束
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9822775.html
Copyright © 2011-2022 走看看