zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 44 (Rated for Div. 2)

    题目链接:https://codeforces.com/contest/985

    ’A.Chess Placing

    题意:给了一维的一个棋盘,共有n(n必为偶数)个格子。棋盘上是黑白相间的。现在棋盘上有n/2个棋子,让你全部移动到黑色格子或者白色格子,要求步数最少,并输出步数。

    题解:由于黑色或者白色都是固定位置,我们对棋子位置排个序,然后全部移动到任意一个颜色,取两个最小步数的最小值就好了。

     1 #include<bits/stdc++.h>
     2 #define clr(x) memset(x,0,sizeof(x))
     3 #define clr_1(x) memset(x,-1,sizeof(x))
     4 #define mod 1000000007
     5 #define INF 0x3f3f3f3f
     6 #define LL long long
     7 #define pb push_back
     8 #define pbk pop_back
     9 #define ls(i) (i<<1)
    10 #define rs(i) (i<<1|1)
    11 #define mp make_pair
    12 using namespace std;
    13 const int N=1e5+10;
    14 int a[N],p[N];
    15 int n,d,ans1,ans2;
    16 int main()
    17 {
    18     scanf("%d",&n);
    19     ans1=ans2=0;
    20     n/=2;
    21     for(int i=1;i<=n;i++)
    22         scanf("%d",p+i);
    23     sort(p+1,p+n+1);
    24     for(int i=1;i<=n;i++)
    25     {
    26        ans1+=abs(p[i]-i*2);
    27        ans2+=abs(p[i]-(i*2-1));
    28     }
    29     printf("%d
    ",min(ans1,ans2));
    30     return 0;
    31 }
    View Code

    B.Switches and Lamps

    题意:有n个开关和m盏灯,每个开关都关联一些灯,按下该开关后这些关联的灯如果亮着就保持不变,关着就会亮起。问你存不存在n-1个开关的组合,使得按下这n-1个开关后,所有灯全部亮起。

    题解:用0和1标记按下开关i后第j个灯是否亮起。然后求每个灯关联的开关数。接着遍历所有开关。如果存在一组开关,使得他对每个灯的亮起标记数全部小于每个灯的关联开关数,则存在这样一个组合,这个组合是除他以外的其他所有开关。

     1 #include<bits/stdc++.h>
     2 #define clr(x) memset(x,0,sizeof(x))
     3 #define clr_1(x) memset(x,-1,sizeof(x))
     4 #define mod 1000000007
     5 #define INF 0x3f3f3f3f
     6 #define LL long long
     7 #define pb push_back
     8 #define pbk pop_back
     9 #define ls(i) (i<<1)
    10 #define rs(i) (i<<1|1)
    11 #define mp make_pair
    12 using namespace std;
    13 const int N=2e3+10;
    14 int a[N],b[N],n,m;
    15 string s[N];
    16 bool flag;
    17 int main()
    18 {
    19     ios::sync_with_stdio(false);
    20     cin.tie(0);
    21     cout.tie(0);
    22     cin>>n>>m;
    23     for(int i=1;i<=n;i++)
    24     {
    25         cin>>s[i];
    26         for(int j=0;j<m;j++)
    27         {
    28             if(s[i][j]=='1')
    29                 a[j+1]++;
    30         }
    31     }
    32     for(int i=1;i<=n;i++)
    33     {
    34         clr(b);
    35         flag=0;
    36         for(int j=0;j<m;j++)
    37             if(s[i][j]=='1')
    38                 b[j+1]++;
    39         for(int j=1;j<=m;j++)
    40             if(b[j]==a[j])
    41             {
    42                 flag=1;
    43                 break;
    44             }
    45         if(flag==0)
    46             return !printf("YES
    ");
    47     }
    48     return !printf("NO
    ");
    49 }
    View Code

    C.Liebig's Barrels

    题意:给你n*k块木板,要你做n个桶,每个桶由k块木板组成。每个桶的盛水量由最短的木板决定。让你最大化这n个木桶的总盛水量,并且每每对木桶的盛水量差不超过l。

    题解:给所有板从小到大排个序,然后看最短板往上n块板是不是都小于等于其长度+l,如果不满足则做不出这样的桶组合。现在我们取n块板来造这n个木桶,作为每个桶的最短板。先算其长度+l的木板所在的位置t,然后从第一块最短板开始,每隔k个取一块板,直到板位置超过了t。然后从t位置往前取,除了前面取过的位置,一个一个地取板。按照上述操作取板,直到取了n块板作为木桶的最短板。这时候盛水量就为这n块板长度和。

     1 #include<bits/stdc++.h>
     2 #define clr(x) memset(x,0,sizeof(x))
     3 #define clr_1(x) memset(x,-1,sizeof(x))
     4 #define mod 1000000007
     5 #define INF 0x3f3f3f3f
     6 #define LL long long
     7 #define pb push_back
     8 #define pbk pop_back
     9 #define ls(i) (i<<1)
    10 #define rs(i) (i<<1|1)
    11 #define mp make_pair
    12 using namespace std;
    13 const int N=1e5+10;
    14 int a[N],b[N],n,m,k,l,t,pp;
    15 LL ans;
    16 int main()
    17 {
    18     ios::sync_with_stdio(false);
    19     cin.tie(0);
    20     cout.tie(0);
    21     cin>>n>>k>>l;
    22     m=n*k;
    23     for(int i=1;i<=m;i++)
    24         cin>>a[i];
    25     sort(a+1,a+m+1);
    26     if(a[n]-a[1]>l)
    27     {
    28         cout<<0<<endl;
    29         return 0;
    30     }
    31     t=upper_bound(a+1,a+m+1,a[1]+l)-a;
    32     ans=0;
    33     t--;
    34     pp=0;
    35     for(int i=1;i<=t && pp<n;i+=k)
    36         ans+=1LL*a[i],pp++;
    37     for(int i=t;i>=1 && pp<n;i--)
    38     {
    39         if(i%k==1)
    40             continue;
    41         else
    42             ans+=1LL*a[i],pp++;
    43     }
    44     printf("%I64d
    ",ans);
    45     return 0;
    46 }
    View Code

    D.Sand Fortress

    题意:给你无穷个点,从左到右为0,1,2,3…+∞。然后给你n块积木往点上放,要求所有相邻两个点间的积木高度差不超过1。并且约束第一堆积木的高度最大值。问你把这n块积木分配到这些点上后,有放积木的点的数量最少为多少?

    题解:如果要求第一堆积木数量最大为1,我们可以想象我们如果要放积木到k堆上积木数最大的情况是形成一个小山一样的,相邻堆差为1的情况。那现在我们约束了第一堆最大高度为h,我们要造k堆。那么积木数最大时,我们第一堆右侧的情况,就是(k+h-1)这个小山中第k堆(包含第k堆)左侧的小山翻转过来的样子。那么我们要求更小的积木数时,就可以通过从上到下拿走积木构成,因此k堆的可达成的积木数是0~这个最大值。对于本题,我们二分查找构成的堆数,用上述方法判断该堆能不能放n个积木,来找到堆数最小值。

    此题还需要一点高精度。

      1 #include<bits/stdc++.h>
      2 #define clr(x) memset(x,0,sizeof(x))
      3 #define clr_1(x) memset(x,-1,sizeof(x))
      4 #define mod 100000000
      5 #define LL long long
      6 #define pb push_back
      7 #define pbk pop_back
      8 #define ls(i) (i<<1)
      9 #define rs(i) (i<<1|1)
     10 #define mp make_pair
     11 using namespace std;
     12 LL n,h,lt,rt;
     13 LL mid;
     14 LL t[50],k[50];
     15 void mul(LL *a,LL p)
     16 {
     17     LL g[50],ans[50];
     18     clr(g);
     19     clr(ans);
     20     g[0]=p%mod;
     21     p/=mod;
     22     g[1]=p%mod;
     23     p/=mod;
     24     g[2]=p%mod;
     25     for(int i=0;i<15;i++)
     26     {
     27         for(int j=0;j<3;j++)
     28             ans[i+j]+=g[j]*a[i];
     29     }
     30     for(int i=0;i<45;i++)
     31         ans[i+1]+=ans[i]/mod,ans[i]%=mod;
     32     for(int i=0;i<50;i++)
     33         a[i]=ans[i];
     34     return ;
     35 }
     36 void add(LL *a,LL p)
     37 {
     38     LL g[50];
     39     clr(g);
     40     g[0]=p%mod;
     41     p/=mod;
     42     g[1]=p%mod;
     43     p/=mod;
     44     g[2]=p%mod;
     45     for(int i=0;i<15;i++)
     46         a[i]=a[i]+g[i];
     47     for(int i=0;i<15;i++)
     48         a[i+1]+=a[i]/mod,a[i]%=mod;
     49     return ;
     50 }
     51 void sub(LL *a,LL *b)
     52 {
     53     for(int i=0;i<45;i++)
     54     {
     55         a[i]-=b[i];
     56         if(a[i]<0)
     57             a[i]+=mod,a[i+1]--;
     58     }
     59     return ;
     60 }
     61 bool cmp(LL *a,LL p)
     62 {
     63     LL g[50];
     64     clr(g);
     65     g[0]=p%mod;
     66     p/=mod;
     67     g[1]=p%mod;
     68     p/=mod;
     69     g[2]=p%mod;
     70     for(int i=49;i>=0;i--)
     71             if(a[i]>g[i]) return true;
     72             else if(a[i]<g[i]) return false;
     73     return true;
     74 }
     75 int main()
     76 {
     77     scanf("%I64d%I64d",&n,&h);
     78     lt=0;
     79     rt=n;
     80     while(rt-lt>1)
     81     {
     82         clr(t);
     83         t[0]=1;
     84         mid=lt+rt>>1;
     85         if(mid<=h)
     86             mul(t,((mid+1)%2==0?(mid+1)/2:(mid+1))),mul(t,mid%2==0?mid/2:mid);
     87         else
     88         {
     89             if((mid+h-1)&1)
     90                 mul(t,(mid+h-1)/2),mul(t,(mid+h+1)/2),add(t,(mid+h-1)/2+1);
     91             else
     92                 mul(t,(mid+h-1)/2),mul(t,(mid+h+1)/2);
     93             clr(k);
     94             k[0]=1;
     95             mul(k,h%2==0?h/2:h);
     96             mul(k,(h-1)%2==0?(h-1)/2:(h-1));
     97             sub(t,k);
     98         }
     99         if(cmp(t,n))
    100             rt=mid;
    101         else
    102             lt=mid;
    103     }
    104     printf("%I64d
    ",rt);
    105     return 0;
    106 }
    View Code

    E.Pencils and Boxes

    题意:给你n个数字,让你把他们随意分配到任意数量的集合里,要求集合内数字的个数不小于k,并且任意两个数字之差不大于d。问是否能找到这样的一种集合构造。

    题解:我们仍旧把数字排个序,可知每个集合包含排序后的一段连续数字。然后从后往前dp,dp他是不是能成为某个集合左端点(最小数字)。如果该数字为集合左端点,则该位置标记1,否则标记0。处理到第i个数字时,我们lower_bound出他的值+d的数字位置t,然后看看[i+k,t+1]位置有没有左端点,如果有,那么该位置也能成为左端点,标记1。由于这个区间可能很大,我们写个最大值线段树来查询这个位置区间。最后如果1能成为左端点,那么说明存在这样的集合构造,否则不存在。

     1 #include<bits/stdc++.h>
     2 #define clr(x) memset(x,0,sizeof(x))
     3 #define clr_1(x) memset(x,-1,sizeof(x))
     4 #define mod 1000000007
     5 #define INF 0x3f3f3f3f
     6 #define LL long long
     7 #define pb push_back
     8 #define pbk pop_back
     9 #define ls(i) (i<<1)
    10 #define rs(i) (i<<1|1)
    11 #define mp make_pair
    12 using namespace std;
    13 const int N=5e5+100;
    14 int n,k,d;
    15 int a[N];
    16 struct node
    17 {
    18     int l,r,maxn;
    19 }tree[N<<2];
    20 void init(int i,int l,int r)
    21 {
    22     tree[i]=(node){l,r,0};
    23     if(l==r) return ;
    24     int mid=l+r>>1;
    25     init(ls(i),l,mid);
    26     init(rs(i),mid+1,r);
    27     return ;
    28 }
    29 void upd(int i,int pos,int val)
    30 {
    31     if(tree[i].l==tree[i].r) {tree[i].maxn=val; return ; }
    32     int mid=tree[i].l+tree[i].r>>1;
    33     if(mid>=pos) upd(ls(i),pos,val);
    34     else upd(rs(i),pos,val);
    35     tree[i].maxn=max(tree[ls(i)].maxn,tree[rs(i)].maxn);
    36     return ;
    37 }
    38 int qy(int i,int l,int r)
    39 {
    40     if(tree[i].l>=l && tree[i].r<=r) return tree[i].maxn;
    41     int mid=tree[i].l+tree[i].r>>1;
    42     int ans=0;
    43     if(l<=mid) ans=max(ans,qy(ls(i),l,r));
    44     if(r>mid) ans=max(ans,qy(rs(i),l,r));
    45     return ans;
    46 }
    47 int main()
    48 {
    49     scanf("%d%d%d",&n,&k,&d);
    50     for(int i=1;i<=n;i++)
    51         scanf("%d",a+i);
    52     sort(a+1,a+n+1);
    53     init(1,1,n);
    54     for(int i=n-k+1;i>=1;i--)
    55     {
    56         int t=upper_bound(a+1,a+n+1,a[i]+d)-a;
    57         t--;
    58         if(t==n) {upd(1,i,1); continue;}
    59         if(i+k>t+1) continue;
    60         upd(1,i,qy(1,i+k,t+1));
    61     }
    62     if(qy(1,1,1)==1) printf("YES
    ");
    63     else printf("NO
    ");
    64     return 0;
    65 }
    View Code

    F.Isomorphic Strings

    题意:给你一个字符串s,然后q个询问。每个询问给出两个该串的子串(长度相同),问能否对每个字母找到一个双射f(x),使得子串1能够通过双射f(x)变成子串2,子串2能通过f(x)反函数f'(x)变为子串1。

    题解:我们把26个字母拆开来,如果该位置有该字母则标1,否则标0,对该字符串做26个字母的双hash。然后询问时,我们对每个询问子串h1,看其内所有出现过的字母在h2里有没有一样的标记序列(hash值)。如果都有那么说明存在这样的双射。如果其中有一个没有那么则不存在。

    为什么双hash? 因为有个大佬造了一组数据卡单hash里的ull情况orz。真的是很强。

     1 #include<bits/stdc++.h>
     2 #define clr(x) memset(x,0,sizeof(x))
     3 #define clr_1(x) memset(x,-1,sizeof(x))
     4 #define LL long long
     5 #define pb push_back
     6 #define pbk pop_back
     7 #define ls(i) (i<<1)
     8 #define rs(i) (i<<1|1)
     9 #define mp make_pair
    10 using namespace std;
    11 const int N=2e5+10;
    12 const int maxn=2e5;
    13 const LL mod[2]={1000000007,987654323};
    14 LL bit[N][2];
    15 LL rk[N][26][2],num[N][26];
    16 int n,m,t,h1,h2,len;
    17 char s[N];
    18 bool flag,rflag;
    19 int main()
    20 {
    21     bit[0][0]=bit[0][1]=1;
    22     for(int i=1;i<=maxn;i++)
    23         for(int j=0;j<2;j++)
    24             bit[i][j]=(bit[i-1][j]<<1)%mod[j];
    25     scanf("%d%d",&n,&m);
    26     scanf("%s",s+1);
    27     for(int i=1;s[i];i++)
    28     {
    29         t=s[i]-'a';
    30         for(int j=0;j<26;j++)
    31         {
    32             for(int k=0;k<2;k++)
    33                 if(t==j)
    34                     rk[i][j][k]=(rk[i-1][j][k]<<1|1)%mod[k];
    35                 else
    36                     rk[i][j][k]=(rk[i-1][j][k]<<1)%mod[k];
    37             if(t==j)
    38                 num[i][j]=num[i-1][j]+1;
    39             else
    40                 num[i][j]=num[i-1][j];
    41         }
    42     }
    43     for(int i=1;i<=m;i++)
    44     {
    45         scanf("%d%d%d",&h1,&h2,&len);
    46         rflag=1;
    47         for(int j=0;j<26;j++)
    48             if(num[h1+len-1][j]>num[h1-1][j])
    49             {
    50                 flag=0;
    51                 for(int k=0;k<26;k++)
    52                 {
    53                     if(((rk[h1+len-1][j][0]-rk[h1-1][j][0]*bit[len][0]%mod[0])%mod[0]+mod[0])%mod[0]==((rk[h2+len-1][k][0]-rk[h2-1][k][0]*bit[len][0]%mod[0])%mod[0]+mod[0])%mod[0] && ((rk[h1+len-1][j][1]-rk[h1-1][j][1]*bit[len][1]%mod[1])%mod[1]+mod[1])%mod[1]==((rk[h2+len-1][k][1]-rk[h2-1][k][1]*bit[len][1]%mod[1])%mod[1]+mod[1])%mod[1] )
    54                     {
    55                         flag=1;
    56                         break;
    57                     }
    58                 }
    59                 if(flag==0)
    60                 {
    61                     rflag=0;
    62                     break;
    63                 }
    64             }
    65         if(rflag)
    66             printf("YES
    ");
    67         else
    68             printf("NO
    ");
    69     }
    70     return 0;
    71 }
    View Code

    G.Team Players

    题意:给出数字0~(n-1),并给出m个数字对,要求你找出所有的三元组(a,b,c),a<b<c,并且其中不能包含这些数字对。然后让你输出所有三元组A*a+B*b+C*c的和。

    题解:我们用容斥定理,把所有三元组和求出来,减去包含至少包含其中一个数字对的三元组的和,加上至少包含其中两个数字对的三元组的和,减掉包含其中三个数字对的三元组的和。最后一个情况要找三元环,通过了大佬的写法才知道怎么有技巧的暴力查找这样的三元环orz。

    由于要mod 2^64,直接用ull去做就好了。

     1 #include<bits/stdc++.h>
     2 #define clr(x) memset(x,0,sizeof(x))
     3 #define clr_1(x) memset(x,-1,sizeof(x))
     4 #define mod 1000000007
     5 #define INF 0x3f3f3f3f
     6 #define LL long long
     7 #define pb push_back
     8 #define pbk pop_back
     9 #define ls(i) (i<<1)
    10 #define rs(i) (i<<1|1)
    11 #define mp make_pair
    12 #define ull unsigned long long
    13 #define fi first
    14 #define se second
    15 using namespace std;
    16 const int N=2e5+10;
    17 ull a,b,c,ans;
    18 vector<int> e[N];
    19 vector<pair<int,int> > pe;
    20 vector<int> g[N];
    21 int n,m,k,t,u,v,r,d;
    22 int sz[N];
    23 ull calc(int p0,int p1,int p2)
    24 {
    25     int st[3]={p0,p1,p2};
    26     sort(st,st+3);
    27     return a*st[0]+b*st[1]+c*st[2];
    28 }
    29 int main()
    30 {
    31     ios::sync_with_stdio(false);
    32     cin.tie(0);
    33     cout.tie(0);
    34     cin>>n>>m;
    35     cin>>a>>b>>c;
    36     ans=0;
    37     for(int i=0;i<n;i++)
    38     {
    39         ans+=a*i*((ull)(n-1-i)*(n-2-i)/2);
    40         ans+=b*i*i*(n-1-i);
    41         ans+=c*i*((ull)i*(i-1)/2);
    42     }
    43     pe.pb(mp(0,0));
    44     for(int i=1;i<=m;i++)
    45     {
    46         cin>>u>>v;
    47         e[u].pb(v);
    48         e[v].pb(u);
    49         pe.pb(mp(u,v));
    50         if(u>v) swap(u,v);
    51         ans-=(a*u+b*v)*(n-1-v)+c*((ull)(v+n)*(n-1-v)/2);
    52         ans-=(a*u+c*v)*(v-u-1)+b*((ull)(u+v)*(v-u-1)/2);
    53         ans-=(b*u+c*v)*u+a*((ull)(u-1)*u/2);
    54     }
    55     for(int i=0;i<n;i++)
    56     {
    57         r=0;
    58         sz[i]=e[i].size();
    59         sort(e[i].begin(),e[i].end());
    60         for(int j=0;j<sz[i];j++)
    61         {
    62             d=e[i][j];
    63             if(d<i)
    64                 ans+=a*d*(sz[i]-1-j)+b*d*j,r++;
    65             else
    66                 ans+=b*d*(sz[i]-1-j)+c*d*j;
    67         }
    68         ans+=a*i*((ull)(sz[i]-r)*(sz[i]-r-1)/2)+b*i*r*(sz[i]-r)+c*i*((ull)r*(r-1)/2);
    69     }
    70     for(int i=1;i<=m;i++)
    71     {
    72         u=pe[i].fi;
    73         v=pe[i].se;
    74         if(sz[u]>sz[v] || (sz[u]==sz[v] && u>v)) swap(u,v);
    75         g[u].pb(v);
    76     }
    77     for(int i=0;i<n;i++)
    78         sort(g[i].begin(),g[i].end());
    79     for(int i=1;i<=m;i++)
    80     {
    81         u=pe[i].fi;
    82         v=pe[i].se;
    83         auto p0=g[u].begin();
    84         auto p1=g[v].begin();
    85         while(p0!=g[u].end() && p1!=g[v].end())
    86             if(*p0==*p1) ans-=calc(u,v,*p0),p0++,p1++;
    87             else if(*p0<*p1) p0++;
    88             else p1++;
    89     }
    90     cout<<ans<<endl;
    91     return 0;
    92 }
    View Code
  • 相关阅读:
    [Luogu5042/UOJ #100][国家集训队互测2015]丢失的题面/ydc的题面
    [51nod1773]A国的贸易
    [GZOI2019&GXOI2019]省选GG记
    [51nod1659]数方块
    [51nod1052]最大M子段和
    [51nod1201]整数划分
    [51nod1084]矩阵取数问题 V2
    [51nod1020]逆序排列
    [BZOJ3000]Big Number
    [BZOJ1684][Usaco2005 Oct]Close Encounter
  • 原文地址:https://www.cnblogs.com/wujiechao/p/9088834.html
Copyright © 2011-2022 走看看