2019牛客暑期多校训练营(第六场)

5 篇文章 0 订阅
5 篇文章 0 订阅

A-Garbage Classification

统计一下个数就可以了

#include <bits/stdc++.h>
using namespace std;
const int N = 2010;
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
char a[N],b[N];
int main()
{
  // freopen("a.in","r",stdin);
  // freopen("a.out","w",stdout);
  int t = read();
  for(int T=1;T<=t;T++)
  {
    printf("Case #%d: ",T);
    scanf("%s",a+1); int alen = strlen(a+1);
    scanf("%s",b+1); int blen = strlen(b+1);
    int d = 0; int w = 0; int h = 0;
    for(int i=1;i<=alen;i++)
	{
	  if(b[a[i] - 'a' + 1] == 'w') w++;
	  if(b[a[i] - 'a' + 1] == 'h') h++;
	  if(b[a[i] - 'a' + 1] == 'd') d++;
    }
    if(h * 4 >= alen){printf("Harmful\n"); continue;}
    else if(h * 10 <= alen){printf("Recyclable\n"); continue;}
    else
    {
      if(d >= 2*w){printf("Dry\n"); continue;}
      else{printf("Wet\n"); continue;}
    }
  }
  return 0;
}

B-Shorten IPv6 Address

字符串坑题,只需要判断一下那个0最长的在中间还是在右边,显然在中间的长度比在右边优秀
:> 0

#include <bits/stdc++.h>
using namespace std;
const int N = 2010;
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
char s[N]; int a[9][5]; int len[9];
void pi(int x)
{
  if(x<=9) printf("%d",x);
  else printf("%c",'a' + x - 10);
}
int main()
{
  #ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
  #endif
  int t = read();
  for(int T=1;T<=t;T++)
  {
    printf("Case #%d: ",T);
    scanf("%s",s); memset(len,0,sizeof(len)); memset(a,0,sizeof(a));
    for(int i=0;i<8;i++) for(int j=0;j<4;j++)
    {
      a[i][j] = ((s[i*16+j*4] - '0') << 3) + ((s[i*16+j*4+1] - '0') << 2) +
        		((s[i*16+j*4+2] - '0') << 1) + (s[i*16+j*4+3] - '0') ;
    }
    
    for(int i=0;i<8;i++){len[i] = 3; for(int j=0;j<4;j++) if(a[i][j] != 0){len[i] = j; break;}}
    int maxlen = 0; int maxpos = -1; int j;
    for(int i=0;i<8;i=j+1)
    {
      j = i; if(len[i] == 3 && a[i][3] == 0)
      {
        while(len[j] == 3 && a[j][3] == 0) j++;
        if(j-i >= maxlen)
		{
		  if(j-i == maxlen && maxpos !=0 && j==8) continue;
		  maxpos = i,maxlen = j-i;
	    }
      }
    }
    
    if(maxlen < 2){maxpos = -1; maxlen = 0;}
    
    int lst = 0;
    for(int i=0;i<8;i=j)
    {
      if(maxpos != i)
      {
        for(int j=len[i];j<4;j++) pi(a[i][j]);
        if(i!=7){printf(":"); lst = 1;} j = i+1;
      }
      else
      {
        if(lst == 0) printf("::"),lst = 0;
        else if(lst == 1) printf(":"),lst = 0;
        j = maxpos + maxlen;
      }
    }
    printf("\n");
  }
  return 0;
}

C-Palindrome Mouse

题目肯定是用回文自动机搞的,然后就是把到当前点的路径上的所有点加上他们所有fail共能到达的点的个数
wcy学长说直接跳fail,拿个vector还原就好了

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define N 100010
using namespace std;
inline ll read()
{
  ll p=0; ll f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
char s[N];
struct Pam
{
  ll fail[N],g[N][26],step[N],last,tot,n;
  void init()
  {
    memset(fail,0,sizeof(fail));
    memset(g,0,sizeof(g));
    memset(step,0,sizeof(step));
    last = n = 0; step[1] = -1; tot = fail[0] = fail[1] = 1;
  }
  void ins(ll nx)
  {
    ll p = last; n++;
    while(s[n-step[p]-1] != s[n]) p = fail[p];
    if(!g[p][nx])
    {
      ll np = ++tot; step[np] = step[p] + 2;
      ll q = fail[p];
      while(s[n-step[q]-1] != s[n]) q = fail[q];
      fail[np] = g[q][nx]; g[p][nx] = np;
    }last = g[p][nx];
  }
}PAM;

vector<ll> v[N];

ll tmp = 0; ll ans = 0; bool vis[N];

void dfs(ll x)
{
  v[x].clear();
  ll q = x; vis[x] = 1; v[x].pb(x);
  while(!vis[PAM.fail[q]]){q = PAM.fail[q]; vis[q] = 1; if(q>1) tmp++; v[x].pb(q);}
  ans += tmp; if(x>1) tmp++;
  for(ll i=1;i<=26;i++) if(PAM.g[x][i])
	dfs(PAM.g[x][i]);
//  printf("%lld :",x);
//  for(ll i=0;i<v[x].size();i++) printf("%lld ",v[x][i]); printf("\n");
  for(ll i=0;i<v[x].size();i++)
  {
    vis[v[x][i]] = 0;
	if(v[x][i] > 1) tmp--;
  }
}

int main()
{
  ll T = read();
  for(ll t=1;t<=T;t++)
  {
    printf("Case #%lld: ",t);
    scanf("%s",s+1); ll len = strlen(s+1); PAM.init();
    for(ll i=1;i<=len;i++) PAM.ins(s[i] - 'a' + 1);
//    for(ll i=0;i<=PAM.tot;i++)
//    {
//      for(ll j=1;j<=26;j++) if(PAM.g[i][j]) printf("%d -> %d\n",i,PAM.g[i][j]);
//    }
//    for(ll i=1;i<=PAM.tot;i++) printf("%d ",PAM.fail[i]);
//    printf("\n");
    ans = tmp = 0;
  	dfs(0);
	dfs(1);
  	printf("%lld\n",ans);
  }
  return 0;
}

D-Move

不满足二分性。。。然后只能暴力,每次其实发现性质只用把下界变成sum/k 只会有k个物品放不下,所以你暴力只要枚举到最大的容量就好了,判断的时候好像n^2比nlogn线段树快。。。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
 
int n,k,a[N];

multiset<int> s;
multiset<int> :: iterator it;

bool check(int x)
{
  s.clear();
  for(int i=1;i<=n;i++) s.insert(a[i]);
  for(int i=1;i<=k;i++)
  {
    int lst = x;
    while(1)
    {
      it = s.upper_bound(lst);
      if(it!=s.begin()) it--;
      else break ;
	  lst -= (*it); s.erase(it); 
    }
  }if(s.size()) return 0;
  return 1;
}

int main()
{
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);
  int t = read();
  for(int T = 1;T<=t;T++)
  {
    n = read(); k = read(); int mx = 0; int s = 0;
    for(int i=1;i<=n;i++) a[i] = read(),mx = max(mx , a[i]) ,s+=a[i];
	int ret = 0;
    for(int mid = max(mx,s/k);;mid++)
    {
      if(check(mid)){ret = mid; break;}
    }printf("Case #%d: %d\n",T,ret);
  }
   
  return 0;
}

E-Androgynos

首先四个顶点的话肯定是一个Z型
考虑在这个基础上构造
一个团的自补图就变成了一个独立集
所以只要构造些团就可以了
考虑n%4=2和n%4=3是肯定不行的

就是以四个顶点来说,一个顶点一块,1块和2块连,2块和3块连,3块和4块连
然后1块和4块内部再自己连自己 所有块之间和块内部都连满就可以了

#include <bits/stdc++.h>
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
#define dep(i,x,y) for(int i=(x);i>=(y);i--)
using namespace std;
const int N = 2020;
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
int a[N][N];
int main()
{
  // freopen("a.in","r",stdin);
  int t = read();
  rep(T,1,t)
  {
    printf("Case #%d: ",T);
    int n = read();
    if(n%4==2 || n%4==3){printf("No\n"); continue;}
    else
    {
      printf("Yes\n");
      rep(i,1,n) rep(j,1,n) a[i][j] = 0;
      int k = n/4;
      rep(i,0,k-1) rep(j,0,k-1)
      {
        if(i!=j) a[i*4][j*4] = a[i*4+3][j*4+3] = 1;
        rep(l,0,2) a[i*4+l][j*4+l+1] = a[i*4+l+1][j*4+l] = 1;
      }
      if(n%4==1){rep(i,0,k-1) a[i*4][n-1] = a[n-1][i*4] = a[i*4+3][n-1] = a[n-1][i*4+3] = 1;}
      
      rep(i,0,n-1){rep(j,0,n-1) printf("%d",a[i][j]); printf("\n");}
      rep(i,0,k-1) printf("%d %d %d %d%c",i*4+2,i*4+4,i*4+1,i*4+3," \n"[(i==k-1) && (n%4==0)]);
      if(n%4==1) printf("%d\n",n);
    }
  }
  return 0;
}

G-Is Today Friday?

正解是直接跑next_permutation,去个重,然后每次都check一遍,跑到不行就停。。
然后有个玄学的蔡勒公式,套进去就可以了在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
inline int read()
{
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

string s[N];
map<string,bool>mp;
int a[N],n;
int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool fd(int y,int m,int d)
{
  if(m>12 || m<1) return 0;
  if((y%400==0) || ((y%100 != 0) && (y%4==0))) day[2] = 29;
  else day[2] = 28;
  
  if(day[m] < d) return 0;
  if(d < 1) return 0;
  
  if(y<1600 || y>9999) return 0;
  
  int w=((d+2*m+3*(m+1)/5+y+y/4-y/100+y/400+1)%7 + 7) % 7;
//  printf("%d %d %d %d\n",y,m,d,w);
  if(w==5) return 1;
  return 0;
}
bool check()
{
  for(int i=1;i<=n;i++)
  {
    int y = a[s[i][0]-'A'+1] * 1000 + a[s[i][1]-'A'+1] * 100 + a[s[i][2]-'A'+1] * 10 + a[s[i][3]-'A'+1];
    int m = a[s[i][5]-'A'+1] * 10 + a[s[i][6]-'A'+1];
    int d = a[s[i][8]-'A'+1] * 10 + a[s[i][9]-'A'+1];
    if(!fd(y,m,d))  return 0;
  }return 1;
}
int main()
{
  int T = read();
  for(int t=1;t<=T;t++)
  {
    printf("Case #%d: ",t);
    n = read(); mp.clear(); int nn = 0;
    for(int i=1;i<=n;i++)
    {
      string str; cin >> str;
      if(mp.find(str) == mp.end()) mp[str] = 1,s[++nn] = str;
    }
    n = nn;
    int m = 1; for(int i=1;i<=10;i++) m = m * i,a[i] = i-1;
    int s = 1; bool bk = 0;
    while(1)
    {
      // for(int i=1;i<=10;i++) printf("%d ",a[i]); printf("\n");
      if(check())
      {
        for(int i=1;i<=10;i++) printf("%d",a[i]); printf("\n");
        bk = 1; break;
      }
	  next_permutation(a+1,a+11); s++;
	  if(s==m+1) break;
    }
    if(!bk) printf("Impossible\n");
  }
  return 0;
}

J-Upgrading Technology

枚举到哪个等级就好了,记得枚举0的等级,维护就瞎维护一下,维护后面的一段最小等等就行了

#include <bits/stdc++.h>
#define N 1010
#define ll long long
using namespace std;
inline ll read()
{
  ll p=0; ll f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
ll c[N][N]; ll d[N]; ll sc[N][N],sd[N],ssc[N];
ll sf[N][N];
int main()
{
  ll T = read();
  for(ll t=1;t<=T;t++)
  {
    printf("Case #%lld: ",t);
    ll n = read(); ll m = read(); // printf("%lld %lld\n",n,m);
    
    memset(c,0,sizeof(c));
    memset(d,0,sizeof(d));
    memset(sd,0,sizeof(sd));
    memset(sc,0,sizeof(sc));
    memset(sf,0,sizeof(sf));
    memset(ssc,0,sizeof(ssc));
    
    for(ll i=1;i<=n;i++) for(ll j=1;j<=m;j++) c[i][j] = read();
    for(ll i=1;i<=m;i++) d[i] = read(),sd[i] = sd[i-1] + d[i];
    for(ll i=1;i<=n;i++)
    {
      sc[i][m] = 0; ll mn = 0;
      for(ll j=m;j>=0;j--){
        mn = mn + c[i][j];
        if(mn > 0) mn = 0;
        if(j) sc[i][j-1] = mn;
        // printf("%lld %lld %lld\n",i,j-1,sc[i][j-1]);
	  }// printf("\n");
	  
	  for(ll j=0;j<=m;j++) sf[i][j] = sf[i][j-1] + c[i][j];
    }
	
    // for(ll i=1;i<=m;i++) printf("%lld ",sd[i]); printf("\n");
    for(ll i=0;i<=m;i++){for(ll j=1;j<=n;j++) ssc[i] += sc[j][i];}
    
    ll ans = 0;
    for(ll i=0;i<=m;i++)
    {
      ll s = sd[i] - ssc[i];
      for(ll j=1;j<=n;j++) s-=sf[j][i];
      for(ll j=1;j<=n;j++) ans = max(ans,s + sc[j][i]);
    }printf("%lld\n",ans);
  }
  return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值