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

A-digits 2

直接n个n拼起来就好了。。。

#include <bits/stdc++.h>
using namespace std;
int main(){
  int T ; cin >> T;
  while(T--){int n; cin >> n; for(int i=1;i<=n;i++) cout<<n; cout<<endl;}
  return 0;
}

B-generator 1

写高精度显然超时
快速幂的时候改成十进制快速幂就行了
矩阵的乘法并不满足欧拉定理

#include <bits/stdc++.h>
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
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 x0,x1,a,b,n,mod;
struct node
{
  ll a[3][3];
  node(){memset(a,0,sizeof(a));}
  friend node operator * (node x,node y)
  {
    node z;
    for(ll i=1;i<=2;i++) for(ll j=1;j<=2;j++) for(ll k=1;k<=2;k++)
      z.a[i][j] = (z.a[i][j] + x.a[i][k] * y.a[k][j] % mod) % mod;
    return z;
  }
  friend node operator ^ (node x,ll k)
  {
    node z; for(ll i=1;i<=2;i++) z.a[i][i] = 1;
    while(k)
    {
      if(k&1)
	  {
	    z=z*x;
	  }
      x=x*x;
	  k>>=1;
    }return z;
  }
}s,p,q;
char ss[1000010];
ll num[1000010]; ll l;

node calc(node p)
{
  node z; for(ll i=1;i<=2;i++) z.a[i][i] = 1;
  for(ll i=1;i<=l;i++)
  {
    z = z*(p^num[i]);
    p = p^(10ll);
  }
  return z;
}

int main()
{
  x0=read(),x1=read(),a=read(),b=read();
  
  scanf("%s",ss+1); l = strlen(ss+1);
  for(ll i=1;i<=l;i++) num[l-i+1] = ss[i] - '0';
  num[1] --; for(ll i=1;i<=l;i++) if(num[i] < 0) num[i+1] --,num[i]+=10; if(num[l] <= 0) l--;
  // for(ll i=1;i<=l;i++) printf("%d",num[i]); printf("\n");
  mod = read();
  
  s.a[1][1] = x1; s.a[1][2] = x0;
  p.a[1][1] = a; p.a[2][1] = b; p.a[1][2] = 1; p.a[2][2] = 0;
  
  q = calc(p);
  // printf("%lld %lld %lld %lld\n",q.a[1][1],q.a[1][2],q.a[2][1],q.a[2][2]);
  
  return printf("%lld\n",(s*q).a[1][1]),0;
}

C-generator 2

没想到这个年头还有BSGS的题
推一波式子:
a n = v ( a 1 ) + b x 0 ( a 1 ) + b m o d &ThinSpace;&ThinSpace; p a^n = \frac{v(a-1)+b}{x_0(a-1)+b} \mod p
然后逆元BSGS就可以了,但是还有点小trick,就是考虑询问不多,我们可以把块的数量分小一点,块的大小分大一点就可以了
其它情况自己判断,注意是到n-1的就行

#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pii;
const ll mod = 1048575;
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 qpow(ll x,ll k,ll p)
{
  ll s = 1;
  while(k)
  {
    if(k&1) s = (s*x) % p;
    x = (x*x) % p; k>>=1;
  }return s;
}

vector<pii>has[mod + 10];
ll s,block;

ll find(ll x)
{
  ll p = x % mod;
  for(ll i=0;i<has[p].size();i++) if(has[p][i].fi == x) return has[p][i].se;
  return -1;
}
void ins(ll x,ll i)
{
  ll p = x % mod; has[p].pb(mp(x,i));
}

void pre(ll a,ll p)
{
  // printf("%lld %lld %lld\n",a,x,p);
 for(ll i=0;i<mod;i++) has[i].clear();
  block = 1000; // printf("%lld\n",b);
  s = 1; ll q = (ll)ceil((double)p/block);
  for(ll i=0;i<q;i++)
  {
    if(find(s) == -1) ins(s,i);
	s = (s*a) % p;
  }
  s = qpow(s,p-2,p);
}
ll BSGS(ll x,ll p)
{
  ll q = (ll)ceil((double)p/block);
  ll s2 = 1; for(ll i=0;i<block;i++)
  {
 	ll nw = find(x*s2%p);
    if(nw != -1) return i*q + nw;
    s2 = (s2 * s) % p;
  }return -1;
}

ll n,x0,a,b,p,q;
int main()
{
  ll T = read();
  while(T--)
  {
    n = read(); x0 = read(); a = read(); b = read(); p = read();
    q = read();
    if(a>1) pre(a,p);
    while(q--)
    {
      ll v = read();
      if(a == 0)
      {
        if(v!=b && v!=x0) printf("-1\n");
        else if(v==x0) printf("0\n");
        else if(v==b && n>1) printf("1\n");
      }
      else if(a == 1)
      {
        if(b == 0 && v!=a) printf("-1\n");
		else if(b == 0 && v==a) printf("0\n");
		ll ans = (((v-x0)%p+p)%p) * qpow(b , p-2 , p) % p;
	    printf("%lld\n",(ans < n) ? ans : -1);
      }
      else
      {
        ll x = (v * (a-1) + b) % p * qpow((x0 * (a-1) + b) % p , p - 2 , p ) % p;
        // printf("%lld\n",x);
        ll ans = BSGS(x,p);
        printf("%lld\n",(ans < n) ? ans : -1);
      }
    }
  }
  return 0;
}

F-maximum clique 1

这个题好像见过?
首先题目就是要求一个一般图最大团,我们可以根据位数的奇偶来分组,发现最多可以形成偶环,所以可以变成二分图
最大团可以变成补图的最大独立集,意思就是把位数差1的连边即可
二分图中最大独立集就可以变成n-最小点覆盖

考虑输出方案,就是要找出是独立集的点,即找出不是最小点覆盖里面的点集

考虑匈牙利二分匹配怎么找到最小点覆盖的点集?
从右边的未匹配点开始,走未匹配边,匹配边,未匹配边。。。。最后走匹配边到右边
把经过的点都标记,左侧的标记点和右侧的未标记点都是最小点覆盖点集里面的点

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N = 5010;
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;
}
struct node
{
  int x,y,nex;
}edge[N*31]; int len,fir[N];

void ins(int x,int y)
{
  len++; edge[len].x=x; edge[len].y=y; edge[len].nex = fir[x]; fir[x] = len;
  len++; edge[len].y=x; edge[len].x=y; edge[len].nex = fir[y]; fir[y] = len;
}

int n; map<int,bool> mp;
int match[N]; bool chw[N];
bool find(int x)
{
  for(int k=fir[x];k!=-1;k=edge[k].nex)
  {
    int y = edge[k].y;
    if(!chw[y])
    {
      chw[y] = 1;
      if(match[y] == 0 || find(match[y]) ){match[y] = x; return 1;}
    }
  }return 0;
}vector<int> ans;
int a[N],b[N],alen,blen;
bool vis[N],gvis[N];
void dfs(int x)
{
  if(vis[x]) return ; vis[x] = 1;
  for(int k=fir[x];k!=-1;k=edge[k].nex)
  {
    int y=edge[k].y;
    if(match[y] != x && match[y] && !vis[y]){vis[y] = 1; dfs(match[y]);}
  }
}
int main()
{
  // freopen("a.out","w",stdout);
  len = 0; memset(fir,-1,sizeof(fir));
  n = read(); alen = blen = 0; for(int i=1;i<=n;i++)
  {
    int x = read();
    if(__builtin_popcount(x) & 1) a[++alen] = x;
    else b[++blen] = x;
  }
  
//  for(int i=1;i<=alen;i++) printf("%d ",a[i]); printf("\n");
//  for(int i=1;i<=blen;i++) printf("%d ",b[i]); printf("\n");
//  printf("%d %d\n",alen,blen);
  
  for(int i=1;i<=alen;i++) for(int j=1;j<=blen;j++) if(__builtin_popcount(a[i]^b[j]) == 1)
  {
    ins(i,alen+j);
//    printf("%d %d\n",i,alen+j);
  }
   
  for(int i=1;i<=alen;i++)
  {
    for(int j=alen+1;j<=n;j++) chw[j] = 0;
    find(i);
  }
  
  for(int i=alen+1;i<=n;i++) match[match[i]] = i;
//  for(int i=1;i<=n;i++) printf("%d ",match[i]); printf("\n");
  for(int i=alen+1;i<=n;i++)
  {
    for(int j=1;j<=n;j++) vis[j] = 0;
    if(match[i] == 0) dfs(i);
    for(int j=1;j<=n;j++) gvis[j] |= vis[j];
  }
  
  for(int i=1;i<=alen;i++) if(!gvis[i]) ans.pb(a[i]);
  for(int i=alen+1;i<=n;i++) if(gvis[i]) ans.pb(b[i-alen]);
  
  printf("%d\n",ans.size());
  for(int i=0;i<ans.size();i++) printf("%d%c",ans[i]," \n"[i==ans.size()-1]);
  
  return 0;
}

G-subsequence 1

从后往前dp,定义 f [ i ] [ j ] [ 0 / 1 / 2 ] f[i][j][0/1/2] 表示到后面的第几个位,匹配到b串的j位,是大,相等,还是小于的方案数
维护个前缀和,然后有0的情况最后减掉就可以了

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
typedef long long ll;
const int N = 3010;
const int mod = 998244353;
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 f[N][N][3],sum[N][N][3];
int main()
{

  int t = read();
  while(t--)
  {
    int n = read(); int m = read();
    for(int i=1;i<=n;i++) scanf("\n%c",&a[i]);
    for(int i=1;i<=m;i++) scanf("\n%c",&b[i]);
    
//    for(int i=1;i<=n;i++) printf("%c",a[i]); printf("\n");
//    for(int i=1;i<=m;i++) printf("%c",b[i]); printf("\n");
    for(int i=0;i<=n+1;i++) for(int j=0;j<=n+1;j++)
	  sum[i][j][0] = sum[i][j][1] = sum[i][j][2] = f[i][j][0] = f[i][j][1] = f[i][j][2] = 0;
	f[n+1][0][1] = 1; sum[n+1][0][1] = 1;
    for(int i=n;i>=1;i--)
    {
      for(int j=1;j<=n-i+1;j++) for(int k=0;k<3;k++)
      {
        if(k==0)
		{
		  int x = a[i];
		  int y = ((m-j+1) > 0) ? b[m-j+1] : 0;
		  if(x<=y) f[i][j][0] = (f[i][j][0] + sum[i+1][j-1][k]) % mod;
		  else f[i][j][2] = (f[i][j][2] + sum[i+1][j-1][k]) % mod;
		}
		else if(k==1)
		{
		  int x = a[i];
		  int y = ((m-j+1) > 0) ? b[m-j+1] : 0;
		  if(x<y) f[i][j][0] = (f[i][j][0] + sum[i+1][j-1][k]) % mod;
		  else if(x==y) f[i][j][1] = (f[i][j][1] + sum[i+1][j-1][k]) % mod;
		  else f[i][j][2] = (f[i][j][2] + sum[i+1][j-1][k]) % mod;
		}
		if(k==2)
		{
		  int x = a[i];
		  int y = ((m-j+1) > 0) ? b[m-j+1] : 0;
		  if(x<y) f[i][j][0] = (f[i][j][0] + sum[i+1][j-1][k]) % mod;
		  else f[i][j][2] = (f[i][j][2] + sum[i+1][j-1][k]) % mod;
		}
      }
      
      for(int j=0;j<=n-i+1;j++) for(int k=0;k<3;k++) sum[i][j][k] = (sum[i+1][j][k] + f[i][j][k]) % mod;
    }
    
    int ans = 0;
    for(int i=m;i<=n;i++) ans = (ans + sum[1][i][2]) % mod;
    
    for(int i=1;i<=n;i++) if(a[i] == '0')
      for(int j=m;j<=n;j++)
//	    printf("%lld %lld %lld\n",i,j,f[i][j][2]);
		ans = (ans + mod - f[i][j][2]) % mod;
    
    printf("%d\n",ans);
  }
  
  return 0;
}

H-subsequence 2

就是把每个字母都变成一个点,判断各种恶心的情况,然后拓扑就完事了

#include <bits/stdc++.h>
#define pb push_back
#define rep(i,a,b) for(ll i=(a);i<=(b);i++)
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;
}
char ss[N]; int tot = 0;
vector<int> v[11]; int yc[N];
struct node
{
  int x,y,nex;
}edge[N*50]; int len,fir[N]; int ru[N];
void ins(int x,int y)
{
  len++; edge[len].x=x; edge[len].y=y; ru[y] ++; edge[len].nex = fir[x]; fir[x] = len;
}
queue<int> q; vector<int> ans;
int main()
{
  int n = read(); int mm = read(); int m = mm*(mm-1)/2; len = 0; memset(fir,-1,sizeof(fir));
  memset(ru,0,sizeof(ru));
  while(m--)
  {
    char a,b;
    scanf("\n%c\n%c",&a,&b); int l = read();
    for(int i=1;i<=l;i++) scanf("\n%c",&ss[i]);
    int x = a-'a'+1; int y = b-'a'+1;
    int sumx=0, sumy=0;
    for(int i=1;i<=l;i++)
    {
      if(ss[i] == a) sumx++;
      if(ss[i] == b) sumy++;
    }
    
    
    if(v[x].size() != 0 && v[x].size() != sumx){printf("-1\n"); return 0;}
	if(v[y].size() != 0 && v[y].size() != sumy){printf("-1\n"); return 0;}
	
	if(v[x].size() == 0) for(int i=1;i<=sumx;i++){tot++; yc[tot] = x; v[x].pb(tot);}
	if(v[y].size() == 0) for(int i=1;i<=sumy;i++){tot++; yc[tot] = y; v[y].pb(tot);}
	
	int p1 = -1; int p2 = -1; int last = 0;
	for(int i=1;i<=l;i++)
	{
	  if(ss[i] == a){p1++; if(last) ins(last,v[x][p1]); last = v[x][p1];}
	  if(ss[i] == b){p2++; if(last) ins(last,v[y][p2]); last = v[y][p2];}
	}
	if(tot > n){printf("-1\n"); return 0;}
  }
  // printf("!");
  if(tot != n){printf("-1\n"); return 0;}
  while(!q.empty()) q.pop();

  for(int i=1;i<=n;i++) if(ru[i] == 0) q.push(i);
  while(!q.empty())
  {
    int x = q.front(); q.pop(); ans.pb(x);
    for(int k=fir[x];k!=-1;k=edge[k].nex)
    {
      int y = edge[k].y;
      ru[y] --; if(ru[y] == 0) q.push(y);
    }
  }
  
  if(ans.size() != n){printf("-1\n"); return 0;}
  else
  {
    for(int i=0;i<ans.size();i++) printf("%c",'a'+yc[ans[i]]-1);
    printf("\n");
  }
  
  return 0;
}

I-three points 1

几何题
肯定有一个点在原点,然后一条线段压在下面,并在下边或者右边(上边或者左边的情况只需把长和宽调换一下即可)
另外一个点其实是可以确定的,但是你要判断一下这个点是在这个线段的上面还是下面
然后点的顺序,输出的顺序都要枚举,YY一下就可以了
把长方形的边界放大,不然会卡精度,左右上下边界放大到1e-12可以过

#include <bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef pair<long double,long double> pii;
const long double eps = 1e-12;
const long double pi = acos(-1);
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;
}

pii p1,p2,p3,q1,q2,q3;
long double w,h; bool bk = 0;

long double dis(pii x,pii y){return sqrt((x.fi-y.fi) * (x.fi-y.fi) + (x.se - y.se) * (x.se - y.se));}
void upd(){q1=p1; q2=p2; q3=p3; bk = 1;}

void solve(long double a,long double b,long double c)
{
  p1 = mp(0.0,0.0);
  
  long double t1;
  if(a <= w) t1 = 0.0 , p2 = mp(a,0);
  else t1 = atan(sqrt(a*a-w*w)/w) , p2 = mp(w,sqrt(a*a-w*w));
  
  if(p2.fi > w+eps || p2.fi < -eps || p2.se > h+eps || p2.se < -eps) return ;
  
  long double c2 = (a*a + b*b - c*c) / (2 * a * b);
  long double t2 = atan(sqrt(1.0/(c2*c2) - 1.0));

  if(t1 + t2 <= pi / 2)
  {
    long double t3 = t1 + t2;
    p3 = mp(cos(t3) * b,sin(t3) * b);
    if(p3.fi <= w+eps && p3.se <= h+eps && p3.fi >= -eps && p3.se >= -eps && fabs(dis(p2,p3) - c) <= eps){upd(); return ;}
  }
  
  if(t1 - t2 >= 0.0)
  {
    long double t3 = t1 - t2;
    p3 = mp(cos(t3) * b,sin(t3) * b);
    if(p3.fi <= w+eps && p3.se <= h+eps && p3.fi >= -eps && p3.se >= -eps && fabs(dis(p2,p3) - c) <= eps){upd(); return ;}
  }
  
}

long double a,b,c;

void check()
{
  solve(a,b,c);
  solve(a,c,b);
  solve(b,a,c);
  solve(b,c,a);
  solve(c,a,b);
  solve(c,b,a);
}

void pr(pii x,pii y,pii z)
{
  printf("%.12Lf %.12Lf %.12Lf %.12Lf %.12Lf %.12Lf\n",x.fi,x.se,y.fi,y.se,z.fi,z.se);
}

void output()
{
  if(fabs(dis(q1,q2) - a) <= eps && fabs(dis(q1,q3) - b) <= eps && fabs(dis(q2,q3) - c) <= eps){pr(q1,q2,q3); return ;}
  if(fabs(dis(q1,q3) - a) <= eps && fabs(dis(q1,q2) - b) <= eps && fabs(dis(q2,q3) - c) <= eps){pr(q1,q3,q2); return ;}
  if(fabs(dis(q2,q1) - a) <= eps && fabs(dis(q2,q3) - b) <= eps && fabs(dis(q1,q3) - c) <= eps){pr(q2,q1,q3); return ;}
  if(fabs(dis(q2,q3) - a) <= eps && fabs(dis(q2,q1) - b) <= eps && fabs(dis(q1,q3) - c) <= eps){pr(q2,q3,q1); return ;}
  if(fabs(dis(q3,q1) - a) <= eps && fabs(dis(q3,q2) - b) <= eps && fabs(dis(q1,q2) - c) <= eps){pr(q3,q1,q2); return ;}
  if(fabs(dis(q3,q2) - a) <= eps && fabs(dis(q3,q1) - b) <= eps && fabs(dis(q1,q2) - c) <= eps){pr(q3,q2,q1); return ;}
}

int main()
{
  int T = read();
  while(T--)
  {
    bk = 0; w = read(); h = read(); a = read(); b = read(); c = read();
    check();
    if(bk){output(); continue;}
    swap(w,h);
    check();
    swap(q1.fi,q1.se); swap(q2.fi,q2.se); swap(q3.fi,q3.se);
    if(bk){output(); continue;}
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/98231308