2019 牛客多校 第五场

题目链接:https://ac.nowcoder.com/acm/contest/885#question 链接

A:

  题意:签到

 

B:

  题意:给出fn的递推关系式和n,求fn。n的范围10^(10^6)

  题解:转化成矩阵连乘,这个数据量10进制优化可以过。 

#include <bits/stdc++.h>
using namespace std; 
typedef long long ll;

const int MAXN=2e6+5;

ll f0, f1, a, b, mod;
char s[MAXN]; 

struct Matrix{
    ll m[2][2]; 
};

Matrix Mul(Matrix a, Matrix b)
{
    Matrix ans; 
    ans.m[0][0]=0; ans.m[0][1]=0; 
    ans.m[1][0]=0; ans.m[1][1]=0;
    for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            for(int k=0; k<2; k++)
                ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j])%mod; 
    return ans;
}

Matrix qpow(Matrix a, ll n)
{
    Matrix ans; 
    ans.m[0][0]=1; ans.m[0][1]=0; 
    ans.m[1][0]=0; ans.m[1][1]=1; 
    while(n)
    {
        if(n&1)
            ans=Mul(ans, a);
        a=Mul(a, a); 
        n>>=1;
    }
    return ans;
}

int main()
{
    cin>>f0>>f1>>a>>b; 
    cin>>s>>mod; 
    int len=strlen(s);
    Matrix ans, coe;
    ans.m[0][0]=1; ans.m[0][1]=0; 
    ans.m[1][0]=0; ans.m[1][1]=1; 
    coe.m[0][0]=a; coe.m[0][1]=b; 
    coe.m[1][0]=1; coe.m[1][1]=0; 
    for(int i=len-1; i>=0;  i--)
    {
        ans=Mul(ans, qpow(coe, s[i]-'0'));
        coe=qpow(coe, 10);
    }
    ll res=(ans.m[1][0]*f1+ans.m[1][1]*f0)%mod;
    cout<<res<<endl;
    return 0;
}
View Code

 

C:(未解决)

  题意:给出fn的递推式,求fn=v时,n为多少。

  题解:不难化简得:

  

    不过如何求n就涉及到了BSGS算法,没搞懂,具体可参见:https://blog.csdn.net/ccsu_cat/article/details/98184813

 

 

G:

  题意:给一个字符串t,一个字符串s,找出s中有多少个子序列大于字符串t

  题解:划分情况,当字串长度大于t的长度时:组合数学直接求。当长度相等时:dp【i】【j】表示s中长度为i的后缀中长度为j的子序列大于t中长度为j的后缀。

     此时,分s【n+1-i】和t【m+1-j】的大小关系进行讨论。注意当j的1的时候特别判定。   

     具体可参考:https://blog.csdn.net/qq_43857314/article/details/98212272

#include <bits/stdc++.h>
using namespace std; 
typedef long long ll;

const int MAXN=3e3+5; 
const ll mod=998244353;

ll dp[MAXN][MAXN], com[MAXN][MAXN]; 
char s[MAXN], t[MAXN];
int n, m;

void make_com()
{
    for(int i=0; i<MAXN; i++)
        com[i][i]=1, com[i][0]=1;
    for(int i=1; i<MAXN; i++)
        for(int j=1; j<MAXN; j++)
            com[i][j]=(com[i-1][j]+com[i-1][j-1])%mod;
}

int main()
{    
    make_com();
    int T;
    for(cin>>T; T--; )
    {
        cin>>n>>m;
        cin>>s+1>>t+1;
                
        //子序列的长度大于m时 
        ll ans1=0;
        for(int i=1; i<=n-m; i++)  //起点
        {
            if(s[i]=='0') continue;
            for(int j=m; j<=n-i; j++)
                ans1=(ans1+com[n-i][j])%mod;    
        }
        
        //长度相等的时候
        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++)
            {
                if(s[i]=='0') dp[i][j]=dp[i-1][j-1];
                if(j==1)
                {
                    if(s[n+1-i]>t[m+1-j]) dp[i][j]=(dp[i-1][j]+com[i-1][j-1])%mod;
                    else dp[i][j]=dp[i-1][j];
                }
                else if(s[n+1-i]>t[m+1-j]) dp[i][j]=(dp[i-1][j]+com[i-1][j-1])%mod;
                else if(s[n+1-i]==t[m+1-j]) dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%mod;
                else dp[i][j]=dp[i-1][j];
            } 
        cout<<(ans1+dp[n][m])%mod<<endl;
    }
    return 0;
} 
View Code

 

H:

  题意:用前m个小写字母构造长度为n的字符串,有(m-1)*m/2个条件,条件是:给出去除字符c1和c2后形成的串,构造一个满足条件的原串,如果没有的话,输出-1

  题解:给出了去除某2个字符后的串,其实就是告诉了我们原串中部分字符的相对顺序,可以通过建图,在拓扑排序输出即可,顺序在后的是入度。(建图的时候错了很多次.)

#include <bits/stdc++.h>
using namespace std;

const int MAXN=1e6+5;
char str[MAXN], s[MAXN];
int n, m, len, all;
int cnt[30]; 
int in[MAXN];
vector<int> edge[MAXN], v[30], ans; 

void make_map()
{
    int pre=-1;
    memset(cnt, 0, sizeof(cnt));
    for(int i=0; i<len; i++)
    {
        int id=str[i]-'a'+1;
        cnt[id]++;
        if(v[id].size()<cnt[id])
        {
            v[id].push_back(++all);
            s[all]=str[i];
        }
        if(pre!=-1)
        {
            edge[pre].push_back(v[id][cnt[id]-1]);
            in[v[id][cnt[id]-1]]++;
        }
        pre=v[id][cnt[id]-1];
    }
}

void topo()
{
    queue<int> q;
    for(int i=1; i<=all; i++)
        if(in[i]==0) q.push(i);
    while(!q.empty())
    {
        int p=q.front(); q.pop();
        ans.push_back(p);
        for(int i=0; i<edge[p].size(); i++)
        {
            int y=edge[p][i];
            in[y]--;
            if(in[y]==0) q.push(y);    
        }
    }
}

int main()
{
    cin>>n>>m; 
    m=(m-1)*m/2;
    while(m--)
    {
        cin>>str>>len;
        if(len) cin>>str;
        else continue;
        make_map();
    }
    topo();
    if(ans.size()==n) 
        for(int i=0; i<n; i++)
            printf("%c", s[ans[i]]);
    else 
        printf("-1");
    
    return 0;
}
View Code

 

I:

  题意:给出一个坐标系中给出一个矩形,和三角形的三条边长,输出满足该三角形完全在矩形内时的三个点的坐标。

  题解:找出最长的边c (假设这里是c)靠在x轴上,一端点在(0, 0), 然后求另一端点如果c>x,则该边向上旋转,直到接触到wh这个矩阵的边,然后设该点为第二个端点。之后你知道了两个点,三条边,就可以求出第三个点。(额,完美的错误想法)

     因为最长的边不一定是这样的(暴力ac代码验证得来的),不过那个三角形大概长成那样,可以直接暴力匹配三角形的边长判断是否满足条件也就6种情况而已。

#include <bits/stdc++.h>
using namespace std;
 
const double eps=1e-8;
  
struct Cod{
    double x, y;
}ans[5];
double w, h, a, b, c;
 
bool solve(double a, double b, double c, int x, int y, int z)
{
    ans[x].x=0, ans[x].y=0;
    if(a<=w)
        ans[y].x=a, ans[y].y=0;
    else
        ans[y].x=w, ans[y].y=sqrt(a*a-w*w);
    double ang=acos((a*a+b*b-c*c)*1.0/(2.0*a*b))+atan(ans[y].y*1.0/ans[y].x);
    ans[z].x=b*cos(ang), ans[z].y=b*sin(ang);
     
    if(ans[z].x>-eps&&ans[z].x<w+eps && ans[z].y>-eps&&ans[z].y<h+eps)
    {
        for(int i=0; i<3; i++)
            printf("%.12f %.12f ", ans[i].x, ans[i].y);
        printf("\n");
        return true;
    }
    return false;      
}
 
int main()
{
    int T;
    for(cin>>T; T--; )
    {
        cin>>w>>h>>a>>b>>c;
        if(solve(a, b, c, 0, 1, 2)) ;
        else if(solve(a, c, b, 1, 0, 2)) ;
        else if(solve(b, a, c, 0, 2, 1)) ;
        else if(solve(b, c, a, 2, 0, 1)) ;
        else if(solve(c, a, b, 1, 2, 0)) ;
        else if(solve(c, b, a, 2, 1, 0)) ; 
//      WA      
//        if     (a>=b && a>=c && (solve(a, b, c, 0, 1, 2) || solve(a, c, b, 1, 0, 2))) ;
//      else if(b>=a && b>=c && (solve(b, a, c, 0, 2, 1) || solve(b, c, a, 2, 0, 1))) ;
//      else if(c>=a && c>=b && (solve(c, a, b, 1, 2, 0) || solve(c, b, a, 2, 1, 0))) ;   
    }  
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/Yokel062/p/11296185.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值