2019 牛客 多校赛 第五场

slove  1/10

rank  615

补题   6/10

--------------------------------------------------------

https://ac.nowcoder.com/acm/contest/885#question

A、digits 2

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n;
		scanf("%d", &n);
		int sum = n;
		while (sum--)
			printf("%d", n);
		printf("\n");
	}
}

B、generator 1

给六个数字x1,x0,a,b,n,mod,对于n>=2,,输出  % mod 的值

方法1、循环节为 ,i 是素数并且是去重后的mod的质因数。(无法证明,问就是能过。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll mod;
struct node
{
    static const ll len = 2;
    ll matrix[len][len];
    node()
    {
        memset(matrix, 0, sizeof matrix);
    }
    void set(ll a[len][len])
    {
        for (int i = 0; i < len; i++)
        {
            for (int j = 0; j < len; j++)
                matrix[i][j] = a[i][j];
        }
    }
    void one()
    {
        for (int i = 0; i < len; i++)
            matrix[i][i] = 1;
    }
    node operator * (node other)
    {
        node ans;
        for (int i = 0; i < len; i++)
        {
            for (int j = 0; j < len; j++)
            {
                for (int k = 0; k < len; k++)
                {
                    ans.matrix[i][j] += matrix[i][k] * other.matrix[k][j] % mod;
                }
            }
        }
        for (int i = 0; i < len; i++)
        {
            for (int j = 0; j < len; j++)
            {
                ans.matrix[i][j] %= mod;
            }
        }
        return ans;
    }
};
node power(node a, __int128 b)
{
    node res;
    res.one();
    while (b)
    {
        if (b & 1)
            res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}
char s[1000005];
__int128 len = 1;
void get(ll n)
{
    for (int i = 2; i <= sqrt(n); i++)
    {
        if (n % i == 0)
        {
            len *= 1LL * (i - 1) * (i + 1);
            while (n % i == 0)
                n /= i;
        }
    }
    if (n > 1)
    {
        len *= 1LL * (n - 1) * (n + 1);
    }
}
int main()
{
    ll a, b, q, w;
    scanf("%lld%lld%lld%lld", &q, &w, &a, &b);
    scanf("%s%lld", s, &mod);
    len=mod;
    get(mod);
    int lens = strlen(s);
    __int128 cnt = 0;
    for (int i = 0; i < lens; i++)
    {
        cnt = (cnt * 10 + s[i] - '0') % len;
    }
    node res;
    ll pre[2][2] = {
        {w,0},
        {q,0}
    };
    res.set(pre);
    node t;
    ll temp[2][2] = {
        {a,b},
        {1,0}
    };
    t.set(temp);
    res = power(t, cnt - 1) * res;
    printf("%lld\n", res.matrix[0][0]);
}

方法2、十进制暴力扫(可以优化为一、二、四、八次方来搞)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll mod;
struct node
{
    static const ll len = 2;
    ll matrix[len][len];
    node()
    {
        memset(matrix, 0, sizeof matrix);
    }
    void set(ll a[len][len])
    {
        for (int i = 0; i < len; i++)
        {
            for (int j = 0; j < len; j++)
                matrix[i][j] = a[i][j];
        }
    }
    void one()
    {
        for (int i = 0; i < len; i++)
            matrix[i][i] = 1;
    }
    node operator * (node other)
    {
        node ans;
        for (int i = 0; i < len; i++)
        {
            for (int j = 0; j < len; j++)
            {
                for (int k = 0; k < len; k++)
                {
                    ans.matrix[i][j] += matrix[i][k] * other.matrix[k][j] % mod;
                    while (ans.matrix[i][j] >= mod)
                    ans.matrix[i][j] -= mod;
                }
            }
        }
        return ans;
    }
};
node power(node a, ll b)
{
    node res;
    res.one();
    while (b)
    {
        if (b & 1)
            res = res * a;
        a = a * a;
        b >>= 1;
    }
    return res;
}
node t[4];
char s[1000005];
node res;
void update()
{
    for (int i = 1; i <= 3; i++)
        t[i] = t[i - 1] * t[i - 1];
}
int main()
{
    ll a, b, q, w;
    scanf("%lld%lld%lld%lld", &q, &w, &a, &b);
    scanf("%s%lld", s, &mod);
    ll pre[2][2] = {
        {a,b},
        {1,0}
    };
    ll tt[2][2] = {
        {w,0},
        {q,0}
    };
    node qq;
    qq.set(tt);
    t[0].set(pre);
    update();
    node res;
    res.one();
    int len = strlen(s);
    for (int i = len - 1; i >= 0; i--)
    {
        int op = s[i] - '0';
        for (int i = 0; i <= 3; i++)
            if (op & (1 << i))
                res = res * t[i];
        t[0] = t[1] * t[3];
        update();
    }
    res = res * qq;
    printf("%lld\n", res.matrix[1][0]);
}

F、maximum clique 1

题意:
给你n个点,每个点有一个数据,然后让你求一个最大团,满足每两个点的相异bit位数大于等于2.输出这个团的点的数目和里面的点
题解:
首先显然从正面看这是个最大团问题,但是明显,最大团求的一(ying)定(gai)会超时,也可能是我太菜了.所以考虑转换成补图求最大独立集问题.那么现在就是建图了.每两个bit相异位数恰为1的点相连一条边.可以使用网络流算法来求解.有一个细节问题就是如果把点分成两边.可以发现两个点可以连一条边必定一个点1的个数为奇数一个点1的个数为偶数,那么就可以分啦,奇数为一边,偶数为一边,然后跑网络流就好啦,

#include<bits/stdc++.h>
#define rep1(i,a,b) for(int i=a;i<=b;++i) 
#define rep2(i,b,a) for(int i=b;i>=a;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pf push_front
#define pob pop_back
#define eb emplace_back
#define pof pop_front
#define sc scanf
#define pr printf
#define ll long long 
using namespace std;
const int MAX = 5e3+5;
const int MAXN = 2e5+5;
const int INF = 0x3f3f3f3f;
int n,m,s,t,u[MAXN],v[MAXN],w[MAXN],q,a[MAX];
int first[MAX],nextt[MAXN];
int cur[MAX],cnt=0,answer=0,deep[MAX];
bool isLeft[MAX];
int read_int() {
	char c;
	int ret = 0, sgn = 1;
	do { c = getchar(); } while ((c < '0' || c > '9') && c != '-');
	if (c == '-') sgn = -1; else ret = c - '0';
	while ((c = getchar()) >= '0' && c <= '9') ret = ret * 10 + (c - '0');
	return sgn * ret;
}
void add(int a,int b,int c){
    u[cnt]=a,v[cnt]=b,w[cnt]=c;
    nextt[cnt]=first[u[cnt]];
    first[u[cnt]]=cnt;++cnt;
}
bool bfs(){
    deque<int>list1;
    list1.eb(s);
    for(int i=1;i<=n+2;++i) deep[i]=0;
    memset(deep,0,sizeof(deep));
    deep[s]=1;
    while(!list1.empty()){
        int now = list1.front();list1.pof();
        if(now==t) return true;
        for(int num = first[now];num!=-1;num=nextt[num]){
            if(!deep[v[num]]&&w[num]>0){
                deep[v[num]]=deep[now]+1; 
                list1.eb(v[num]);
            }
        }
    }
    return false;
}
int dfs(int now,int limit){
    if(!limit||now==t) return limit;
    int flow=0,length=0;
    for(int &num = cur[now];num!=-1;num=nextt[num]){
        if(w[num]&&deep[v[num]]==deep[now]+1 && (length = dfs(v[num],min(limit,w[num])))){
        	w[num]-=length;
            w[num^1]+=length;
            flow+=length;
            limit-=length;
            if(!limit) break;
        }
    }
    if(flow) return flow;
    deep[now]=-1;
    return 0;
}
void dinic(){
    while(bfs()){
    	for(int i=1;i<=n+2;++i) cur[i]=first[i];
    	int d = dfs(s,INF);
    	if(!d) break;
    	answer+=d;
	}
}
int oneCount(int num){
	int count=0;
	while(num){
		if(num&1) ++count;
		num>>=1;
	}
	return count; 
}

void solve(){
	n = read_int();
//	scanf("%d",&n);
   	s=n+1,t=n+2,cnt=0,answer=0;
   	for(int i=1;i<=n+2;++i) first[i]=-1;
   	for(int i=1;i<=n;++i){
   		a[i]=read_int();
//   		scanf("%d",&a[i]);
   		if(oneCount(a[i])&1) isLeft[i]=true;
   		if(isLeft[i]) add(s,i,1),add(i,s,0);
   		else add(i,t,1),add(t,i,0);
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(oneCount(a[i]^a[j])==1){
				if(isLeft[i]) add(i,j,1),add(j,i,0);
				else add(j,i,1),add(i,j,0);
			}
		}
	}
   	dinic();
   	int ans = n-answer;
   	printf("%d\n",ans);
	for(int i=1;i<=n;++i){
		if(deep[i]!=0&&isLeft[i]) printf("%d ",a[i]);
		else if(deep[i]==0&&!isLeft[i]) printf("%d ",a[i]);
	}
	printf("\n");
}
int main(void)
{
    solve();
    return 0;
}

G、subsequence 1

题意:
        给出两个字符串s1 s2 求出s1中子序列大于s2的子序列个数

jzk做法

从后往前枚举大于等于m的子串的数量,再算出所有大于长度大于m的子串

#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
const ll mod = 998244353;
const int MAXN = 3005;
using namespace std;
ll C[MAXN][MAXN];
ll dp[MAXN][MAXN];
void init()
{
	for (int i = 0; i < MAXN; i++)
		C[i][0] = 1;
	for (int i = 1; i < MAXN; i++)
		for (int j = 1; j <= i; j++)
			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mod;
}
char s1[MAXN], s2[MAXN];
int main()
{
	init();
	int T;
	sc("%d", &T);
	while (T--)
	{
		int n, m;
		sc("%d%d", &n, &m);
		sc("%s%s", s1, s2);
		for (int i = 0; i <= n; i++)
			for (int j = 0; j <= m; j++)
				dp[i][j] = 0;
		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= i && j <= m; j++)
			{
				dp[i][j] = dp[i - 1][j];
				if (s1[n - i] == s2[m - j])//首字母相等,等于之前选的数量
					dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % mod;
				else if (s1[n - i] > s2[m - j])//首字母大于,随便选
					dp[i][j] = (dp[i][j] + C[i - 1][j - 1]) % mod;
			}
		}
		ll ans = dp[n][m];//长度等于m的大于s2串的个数
		for (int i = 1; i <= n; i++)//长度大于m的个数
			if (s1[i - 1] != '0')
				for (int j = m; j <= n - i; j++)
					ans = (ans + C[n - i][j]) % mod;
		pr("%lld\n", ans);
	}
}

--------------------------------------------------------

dh做法
做法:
       首先考虑如果子序列长度大于s2的长度则必定大于。这一部分可以用组合数的方式直接算出来。然后便是考虑长度相等的情况,这一部分考虑DP 第二维表示的是子序列长度,第三维表示的是在长度相等的情况下,0代表s1子序列在长度相等的情况下值相等s2,1代表s1子序列在长度相等的情况下值大于s2
 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int MOD = 998244353;
const int N = 3005;
ll dp[N][N][2];
ll C[N][N];
char s1[N], s2[N];
int main()
{
	for (int i = 1; i < N; i++)
	{
		C[i][0] = C[i][i] = 1;
		for (int j = 1; j < i; j++)
		{
			C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
			if (C[i][j] >= MOD) 
				C[i][j] -= MOD;
		}
	}
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int m, n;
		scanf("%d %d", &m, &n);
		scanf("%s %s", s1+1, s2+1);
        for(int i = 0;i<=m;i++)
            for(int j = 0;j<=n;j++)
                for(int k = 0;k<=1;k++)
                    dp[i][j][k] = 0;
		dp[0][0][0] = 1;
		for (int i = 1; i <= m; i++)
		{
			for (int j = 0; j <= n; j++)
				for (int k = 0; k <= 1; k++)
					dp[i][j][k] = dp[i - 1][j][k];
			for (int j = 1; j <= n; j++)
			{
				for (int k = 0; k <= 1; k++)
				{
					if (k == 0 && s1[i] < s2[j])
						continue;
					if (k == 0 && s1[i] == s2[j])
						(dp[i][j][k] += dp[i - 1][j - 1][k]) %= MOD;
					else
						(dp[i][j][1] += dp[i - 1][j - 1][k]) %= MOD;
				}
			}
		}
		ll ans = dp[m][n][1];
		for(int i = 1;i<=m;i++)
			if (s1[i] != '0')
			{
				for (int j = n; i + j <= m; j++)
					(ans += C[m - i][j]) %= MOD;
			}
		printf("%lld\n", ans);
	}
}
/*
3
4 2
1234
13
*/

 

H、subsequence 2

题意:大概就是原来有一个隐藏字符串,然后给你n个字符串,然后把那个给出字符串中没出现的字母在隐藏字符串中删掉,然后就得到了这个字符串,然后让你根据这n个字符串求原来的隐藏字符串
题解:
直接根据给出的字符串建立拓扑序,给每个出现的字母编号,比如说给出的字符串为:
bbc
ac
abb
那么编号就是
123
43
412
然后求出拓扑序列,这里的拓扑序为4123,那么明显字符串为abbc(没考虑长度限制!!不要和题目里的样例搞混了,因为样例里是不可以的,因为样例里长度只能为3).

#include<bits/stdc++.h>
using namespace std;
const int MAX = 1e6+5;
const int MAXN = 1e2+5;
int n,m,len,tot=0;
char s1[MAXN],s2[MAX];
bool vis[30],visit[MAX];
int mp[MAX];
int indexMy[30][MAX],cnt[30],now[30],pre,du[MAX];
int first[MAX],nextt[MAX],u[MAX],v[MAX],total=0;
vector<int> ans;
void add(int a,int b){
    u[total]=a,v[total]=b;
    nextt[total]=first[u[total]];
    first[u[total]]=total;++total;
}
void topology(){
    deque<int> list1;
    for(int i=0;i<tot;++i){
        if(du[i]==0){
            list1.push_back(i);
        }
    }
    while(!list1.empty()){
        int now = list1.front();
        list1.pop_front();
        ans.push_back(now);
        for(int num = first[now];num!=-1;num=nextt[num]){
            --du[v[num]];
            if(du[v[num]]==0){
                list1.push_back(v[num]);
            }
        }
    }
}
void solve(){
    memset(cnt,0,sizeof(cnt));
    memset(vis,false,sizeof(vis));
    memset(first,-1,sizeof(first));
    memset(visit,false,sizeof(visit));
    memset(du,0,sizeof(du));
    scanf("%d%d",&n,&m);
    for(int i=0;i<m*(m-1)/2;++i){
        memset(now,0,sizeof(now));
        scanf("%s%d",s1+1,&len);
        if(len!=0) scanf("%s",s2+1);
        for(int j=1;s2[j];++j){
            if(!vis[s2[j]-'a']){
                mp[tot]=s2[j]-'a';
                indexMy[s2[j]-'a'][cnt[s2[j]-'a']++]=tot++;
            }
            if(j!=1){
                int a = pre,b = indexMy[s2[j]-'a'][now[s2[j]-'a']];
                add(a,b);
                ++du[b];
            }
            pre = indexMy[s2[j]-'a'][now[s2[j]-'a']];
            ++now[s2[j]-'a'];
        }
        for(int j=1;s1[j];++j) vis[s1[j]-'a']=true;
    }
//  printf("tot = %d\n",tot);
//  printf("mp:\n");
//  for(int i=0;i<tot;++i){
//      printf("%c ",(char)(mp[i]+'a'));
//  }
//  printf("\n");
//  for(int i=0;i<26;++i){
//      printf("%c: ",(char)(i+'a'));
//      for(int j=0;j<cnt[i];++j){
//          printf("%d ",indexMy[i][j]);
//      }
//      printf("\n");
//  }
    topology();
    if(ans.size()!=n){
        printf("-1\n");
        return;
    }
    for(int i=0;i<ans.size();++i){
        printf("%c",(char)(mp[ans[i]]+'a'));
    }
}
int main(void)
{
    solve();
    return 0;
}

I、three points 1

题意,给一个三角形的三边和矩形的长宽,问三角形能否完全放入矩形

1、首先三角形至少有一个顶点与矩形的顶点重合,并且除了这个点至少有一个点在矩形的边上,所以就可以暴力,三角函数乱搞。

2、注意要按照顺序输出三个点,WA到自闭

#include <bits/stdc++.h>
const double eps = 1e-8;
const double PI = acos(-1.0); // PI = 180°= 3.14 
using namespace std;
int sign(double x)
{
	if (fabs(x) < eps)
		return 0;
	return x > 0 ? 1 : -1;
}

struct point
{
	double x;
	double y;
	void print() { printf("%.12lf %.12lf ", x, y); }
	void println() { printf("%.12lf %.12lf\n", x, y); }
};
double getlen(point a, point b)
{
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
bool check(point a, double w, double h)
{
	if (sign(a.x - w) <= 0 && sign(a.x) >= 0 && sign(a.y - h) <= 0 && sign(a.y) >= 0)
		return true;
	return false;
}
bool judge(double w, double h, double a, double b, double c, int op)
{
	point one = point{ 0,0 };
	point two, ans;
	double anglec = acos((a * a + b * b - c * c) / (2 * a * b));
	if (a <= h)
		two = point{ 0,a };
	else
		two = point{ sqrt(a * a - h * h) ,h };
	double angle = acos((a * a + c * c - b * b) / (2 * a * c)) + atan(two.x / two.y);
	ans.x = c * sin(angle);
	ans.y = c * cos(angle);
	if (check(ans, w, h) && check(two, w, h))
	{
		switch (op)
		{
		case 0: two.print(), one.print(), ans.println(); break;
		case 1:	one.print(), two.print(), ans.println(); break;
		case 2:	two.print(), ans.print(), one.println(); break;
		case 3:	one.print(), ans.print(), two.println(); break;
		case 4: ans.print(), two.print(), one.println(); break;
		case 5:	ans.print(), one.print(), two.println(); break;
		}
		return false;
	}
	return true;
}
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		double w, h, a, b, c;
		scanf("%lf%lf%lf%lf%lf", &w, &h, &a, &b, &c);
		if (judge(w, h, a, b, c, 0))
			if (judge(w, h, a, c, b, 1))
				if (judge(w, h, b, a, c, 2))
					if (judge(w, h, b, c, a, 3))
						if (judge(w, h, c, a, b, 4))
							judge(w, h, c, b, a, 5);
	}
}

 

全部评论

相关推荐

牛客410815733号:这是什么电影查看图片
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务