Codeforces CodeCraft-20

小号冲黄失败...心塞塞_(:з」∠)_

 

1316A - Grade Allocation

\(ans=min(m,\sum_{i=1}^n a_i)\)

#include<bits/stdc++.h>
using namespace std;
int T,n,m,a[1111];
int main()
{
    scanf("%d",&T);
    while(T--)
      {
      int s=0;
      scanf("%d%d",&n,&m);
      for(int i=1;i<=n;i++)
        scanf("%d",&a[i]),s=min(m,s+a[i]);
      printf("%d\n",s);
      }
}
View Code

 

1316B - String Modification

可以试着找找规律,以下列出\(n=4,5,6,7,8\  k=4\)时的结果

\(1234\rightarrow  4321\)

\(12345\rightarrow  45123\)

\(123456\rightarrow  456321\)

\(1234567\rightarrow  4567123\)

\(12345678\rightarrow  45678321\)

应该就能猜出结论了,枚举\(k\)即可

#include<bits/stdc++.h>
using namespace std;
int T,n,ans;
string s,mn;
string rua(int k)
{
    if(k==n)
      {
      string res=s;
      reverse(res.begin(),res.end());
      return res;
      }
    int t=n-k+1;
    if(t%2==0)
      {
      string res=s.substr(k-1,n-k+1);
      res+=s.substr(0,k-1);
      return res;
      }
    string res=s.substr(k-1,n-k+1);
    string tmp=s.substr(0,k-1);
    reverse(tmp.begin(),tmp.end());
    res=res+tmp;
    return res;
}
int main()
{
    scanf("%d",&T);
    while(T--)
      {
      scanf("%d",&n);
      cin>>s;
      ans=1,mn=s;
      for(int i=2;i<=n;i++)
        if(rua(i)<mn)mn=rua(i),ans=i;
      cout<<mn<<endl<<ans<<endl;
      }
}
View Code

 

1316C - Primitive Primes

设\(\left \{ a_n \right \}\)中第一个不被\(p\)整除的数为\(a_i\),\(\left \{ b_m \right \}\)中第一个不被\(p\)整除的数为\(b_j\),则答案为\(i+j\)

证明:考虑所有满足\(0\le x < n, 0 \le y <m, x+y=i+j\)的数对\((x,y)\),显然\(x<i\)和\(y<j\)这两个不等式至少有一个成立,故\(a_x \cdot b_y\)必定为\(p\)的倍数。又由于\(p\)为质数,所以\(a_i \cdot b_j\)一定不为\(p\)的倍数,结论成立

#include<bits/stdc++.h>
using namespace std;
#define N 1000001
int n,m,p,a[N],b[N],l,r;
int main()
{
    scanf("%d%d%d",&n,&m,&p);
    for(int i=0;i<n;i++)
      scanf("%d",&a[i]);
    for(int i=0;i<m;i++)
      scanf("%d",&b[i]);
    while(a[l]%p==0)l++;
    while(b[r]%p==0)r++;
    printf("%d\n",l+r);
}
View Code

 

1316D - Nash Matrix

对所有\(a[i][j]=(i,j)\)的点,设该点为'X',进行BFS,若周围有以该点为终点的点则加入队列,并将其指向上一个点

对所有\(a[i][j]=(-1,-1)\)的点,寻找一个与它相邻且同样为\((-1,-1)\)的点,若有解则一定能找到。这时可以令这两个点互相可达(造成死循环),同样把这两个点加入队列,进行类似的BFS即可

最后如果有未被赋值的点则无解

#include<bits/stdc++.h>
using namespace std;
#define N 1010
int n,x,y,a[N][N];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
char ans[N][N],f[4]={'L','U','R','D'};
queue<int>q;
int id(int x,int y){return (x+1)*N+y;}
void rua(int x,int y)
{
    if(ans[x][y]!='I')return;
    if(a[x][y]<0)
      for(int i=0;i<4;i++)
        {
        int nxtx=x+dx[i],nxty=y+dy[i];
        if(nxtx<1 || nxtx>n || nxty<1 || nxty>n)continue;
        if(a[nxtx][nxty]==a[x][y])
          {
          ans[nxtx][nxty]=f[i];
          ans[x][y]=f[(i+2)%4];
          q.push(id(x,y));
          q.push(id(nxtx,nxty));
          break;
          }
        }
    else ans[x][y]='X',q.push(id(x,y));
    while(!q.empty())
      {
      int cur=q.front();
      q.pop();
      x=cur/N-1,y=cur%N;
      for(int i=0;i<4;i++)
        {
        int nxtx=x+dx[i],nxty=y+dy[i];
        if(nxtx<1 || nxtx>n || nxty<1 || nxty>n)continue;
        if(a[nxtx][nxty]==a[x][y] && ans[nxtx][nxty]=='I')
          ans[nxtx][nxty]=f[i],q.push(id(nxtx,nxty));
        }
      }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        {
        scanf("%d%d",&x,&y);
        a[i][j]=id(x,y);
        ans[i][j]='I';
        }
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        if(a[i][j]==id(i,j) || a[i][j]<0)rua(i,j);
    for(int i=1;i<=n;i++)
      for(int j=1;j<=n;j++)
        if(ans[i][j]=='I')return printf("INVALID\n"),0;
    printf("VALID\n");
    for(int i=1;i<=n;i++)
      {
      for(int j=1;j<=n;j++)
        printf("%c",ans[i][j]);
      printf("\n");
      }
}
View Code

 

1316E - Team Building

首先对所有人按\(a_i\)降序排序,进行状压DP。设\(f[i][bit]\)为前\(i\)个人,已经确定位置的状态为\(bit\)时的最优解,进行转移即可

#include<bits/stdc++.h>
using namespace std;
#define N 100001
#define LL long long
LL n,p,k,f[N][128];
struct rua
{
    LL v,s[8];
    bool operator <(const rua &t)const{return v>t.v;}
}a[N];
int main()
{
    scanf("%lld%lld%lld",&n,&p,&k);
    for(LL i=1;i<=n;i++)scanf("%lld",&a[i].v);
    for(LL i=1;i<=n;i++)
      for(LL j=0;j<p;j++)
        scanf("%lld",&a[i].s[j]);
    sort(a+1,a+n+1);
    for(LL b=0;b<(1<<p);b++)f[0][b]=-1e18;
    f[0][0]=0;
    for(LL i=1;i<=n;i++)
      for(LL b=0,cnt=0;b<(1<<p);b++,cnt=0)
        {
        f[i][b]=-1e18;
        for(LL k=0;k<p;k++)if((1ll<<k)&b)
          cnt++,f[i][b]=max(f[i][b],f[i-1][(1ll<<k)^b]+a[i].s[k]);
        f[i][b]=max(f[i][b],f[i-1][b]+(i<=cnt+k?a[i].v:0));
        }
    printf("%lld\n",f[n][(1<<p)-1]);
}
View Code

 

1316F - Battalion Strength

看了几份AC代码,大概知道了其中一种做法,先讲一下大致思路等白天起床再写_(:з」∠)_

首先对\(p_i\)排序,先考虑不修改的时候答案是多少

对于任意两对数\(p_i, p_j, i<j\),若这两个数相邻,则其产生的价值为\(p_i \cdot p_j\),而能让这两个数相邻的子集数则为\(2^{n-(j-i+1)}\),其中\(n-(j-i+1)\)表示把区间\([i,j]\)掏空后的元素个数。这样我们可以得到\(2^n\cdot ans=\sum_{i=1}^n\sum_{j=i+1}^n p_i\cdot p_j \cdot 2^{n-j+i-1}\),稍微化简一下可以得到\(2\cdot ans=\sum_{i=1}^n\sum_{j=i+1}^n p_i\cdot p_j \cdot 2^{-j+i}=\sum_{i=1}^n\sum_{j=i+1}^n p_i\cdot 2^i \cdot p_j \cdot 2^{-j}\),这个时候我们就可以用线段树来求解,合并的式子为\(ans=l_{ans}+r_{ans}+l_{s1}\cdot r_{s2}\),\(s1,s2\)分别表示\(p_i\)乘上\(2^i\)和\(2^{-i}\)的和

对于有修改的情况,可以考虑离线处理

得到所有的修改的信息后,对\(p_i\)和修改的值混在一起进行排序,开一个\(n+q\)大小的线段树,并额外记录区间内有多少个位置有值。每次修改就相当于把其中一个位置变为\(0\),另外一个空位变成想要修改的值即可,这样仍然能够保证内部的值是升序排列的,把之前的式子稍作改动即可(额外考虑区间内非空位的个数带来的指数影响)

upd:过了_(:з」∠)_具体做法稍微有点偏差,详细题解随后更

#include<bits/stdc++.h>
using namespace std;
#define N 600001
#define MOD 1000000007
int n,m,p[N],q[N],I[N],v;
struct pi
{
    int v,id;
    void read(int i){scanf("%d",&v),id=i;}
    bool operator <(const pi &t)const{return v<t.v;}
}a[N];
struct rua
{
    int c,ans,sl,sr;
}t[N<<2];
void change(int x,int i,int l,int r,int o)
{
    if(l==r)
      {
      t[i].c=o;
      t[i].ans=t[i].sl=t[i].sr=0;
      if(o)t[i].sl=t[i].sr=1ll*I[1]*a[x].v%MOD;
      return;
      }
    int mid=l+r>>1,ls=i*2,rs=ls+1;
    if(x<=mid)change(x,ls,l,mid,o);
    else change(x,rs,mid+1,r,o);
    t[i].c=t[ls].c+t[rs].c;
    t[i].sl=(1ll*t[ls].sl*I[t[rs].c]+t[rs].sl)%MOD;
    t[i].sr=(1ll*t[rs].sr*I[t[ls].c]+t[ls].sr)%MOD;
    t[i].ans=(t[ls].ans+t[rs].ans+1ll*t[ls].sl*t[rs].sr)%MOD;
}
int main()
{
    I[0]=1,I[1]=(MOD+1)/2;
    for(int i=2;i<N;i++)
      I[i]=1ll*I[1]*I[i-1]%MOD;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      a[i].read(i),p[i]=i;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
      {
      scanf("%d",&q[i]);
      a[n+i].read(n+i);
      p[n+i]=n+i;
      }
    sort(a+1,a+n+m+1);
    for(int i=1;i<=n+m;i++)
      p[a[i].id]=i;
    for(int i=1;i<=n;i++)
      change(p[i],1,1,n+m,1);
    printf("%d\n",t[1].ans);
    for(int i=1;i<=m;i++)
      {
      change(p[q[i]],1,1,n+m,0);
      change(p[n+i],1,1,n+m,1),p[q[i]]=p[n+i];
      printf("%d\n",t[1].ans);
      }
}
View Code

 upd2[CodeCraft-20 (Div. 2)][Codeforces 1316F. Battalion Strength]

posted @ 2020-03-05 05:06  DeaphetS  阅读(413)  评论(0编辑  收藏  举报