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

B:https://ac.nowcoder.com/acm/contest/885/B

矩阵快速幂,A^n,n特别大,想到求某数sum=sum*10+s[i]-'0';

可以把n一位一位拆开,ans=ans^10   *  st^(s[i]-'0'),指数相加所以分开相乘

十进制优化类似快速幂!!!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e6+5;
ll x0,x1,aa,b,mod;
char n[maxn];
struct mat
{
    ll a[3][3];
};
mat mm[15];
mat mul(mat p,mat q)
{
    mat ans;
    memset(ans.a,0,sizeof(ans.a));
    for(ll i=1;i<=2;i++){
        for(ll j=1;j<=2;j++){
            for(ll k=1;k<=2;k++){
                ans.a[i][j]=(ans.a[i][j]+p.a[i][k]*q.a[k][j])%mod;
            }
        }
    }
    return ans;
}
mat qpow(mat st,ll y)
{
    mat ans;
    ans.a[1][1]=1;ans.a[1][2]=0;ans.a[2][1]=0;ans.a[2][2]=1;
    while(y){
        if(y&1){
            ans=mul(ans,st);
        }
        st=mul(st,st);
        y>>=1;
    }
    return ans;
}
void fun(mat st)
{
    mm[0].a[1][1]=mm[0].a[2][2]=1;
    mm[0].a[1][2]=mm[0].a[2][1]=0;
    for(ll i=1;i<=9;i++){
        mm[i]=mul(mm[i-1],st);
    }
}
int main()
{
    scanf("%lld%lld%lld%lld",&x0,&x1,&aa,&b);
    scanf("%s%lld",&n,&mod);
    mat st,ans;
    st.a[1][1]=aa;st.a[1][2]=1;st.a[2][1]=b;st.a[2][2]=0;
    fun(st);
    ans.a[1][1]=1;ans.a[1][2]=0;ans.a[2][1]=0;ans.a[2][2]=1;
    ll len=strlen(n);
    for(ll i=0;i<len;i++){
        ans=qpow(ans,10);
        ans=mul(ans,mm[n[i]-'0']);
    }
    mat res;
    res.a[1][1]=x1,res.a[1][2]=x0,res.a[2][1]=0,res.a[2][2]=0;
    ans=mul(res,ans);
    printf("%lld\n",ans.a[1][2]);
    return 0;
}

C:https://ac.nowcoder.com/acm/contest/885/C

xi​=(a⋅xi−1​+b)modp.给出一个值,询问等于该值的是第几个。

根据表达式退出xi项,要求的是下标,化简完n在指数位置所以用BSGS算法 ,y^x==z(mod p) 求x值。

把x换成am-b,先求出zy^b的所有值,判断y^am是否存在。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int t1 = 2e3+7, t2 = 5e5+7;
unordered_map<int, int> mp;
long long n;
int x, a, b, p, q;
int pw(int w, int t)
{
    int r = 1;
    while(t){
        if(t % 2)
            r = (ll)r * w % p;
        w = (ll)w * w % p;
        t /= 2;
    }
    return r;
}
void query()
{
    int v;
    scanf("%d", &v);
    if(a == 0){
        printf("%d\n", v==x&&n>0 ? 0:(v==b&&n>1 ? 1:-1));
        return;
    }
    if(a == 1){
        v = (ll)(v - x + p) * pw(b, p-2) % p;
        printf("%d\n", v < n ? v : -1);
        return;
    }
    int y = (ll)b * pw(a-1, p-2) % p;
    v = (ll)(v + y) * pw(y+x, p-2) % p;
    int r = p;
    for(int i = 1; i <= t1; i++){
        v = (ll)v * a % p;
        if(mp.count(v))
            r = min(r, mp[v]-i);
    }
    printf("%d\n", r<p && r<n ? r : -1);
}
void get_res(){
    scanf("%lld%d%d%d%d%d", &n, &x, &a, &b, &p, &q);
    int s = pw(a, t1), k = 1;
    mp.clear();
    for(int i = 1; i <= t2; i++){
        k = (ll)k * s % p;
        if(!mp.count(k))
            mp[k] = i * t1;
    }
    while(q-- > 0)
        query();
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t-- > 0)
        get_res();
    return 0;
 }

G:https://ac.nowcoder.com/acm/contest/885/G

题意:给出n,m,分别是s串,t串的长度,求s串的子序列数量,满足组成的数字比t串表示的数字大。

当子序列长度大于t串时,直接用组合数处理

当子序列长度等于t串时,dp[i][j]表示s串长度为j+1,t串长度为i+1的位置,当前可拼出等于t串的数量

                                        当s[j]>t[i]时,表示这个字符串已经大于t串,剩余的位直接取即可,直接加到答案中。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=3005;
const ll mod=998244353;
ll c[maxn][maxn],dp[maxn][maxn];
void f()
{
    for(ll i=0;i<=3000;i++){
        c[i][0]=1;
        for(ll j=1;j<=i;j++){
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
        }
    }
}
int main()
{
    f();
    ll tt,n,m;
    string s,t;
    cin>>tt;
    while(tt--){
        cin>>n>>m;
        cin>>s>>t;
        s='a'+s;t='a'+t;
        ll ans=0;
        for(ll i=1;i<=n;i++){
            if(s[i]=='0') continue;
            else{
                for(ll j=m;j<=n-i;j++)
                     ans+=(c[n-i][j]%mod);
                     ans%=mod;
            }
        }
        for(ll i=0;i<=n;i++){
            for(ll j=0;j<=m;j++){
                dp[j][i]=0;
            }
        }
        for(ll i=0;i<=n;i++)
            dp[0][i]=1;
        for(ll j=1;j<=n;j++){
            for(ll i=1;i<=m;i++){
                dp[i][j]=dp[i][j-1];//不取这一位时,前面有的
                if(s[j]==t[i]){
                    //可以取这一位,前面的有多少项满足条件
                    //可增加一位,直接加dp[i-1][j-1]
                    dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
                }
                else if(s[j]>t[i]){
                    ans+=(dp[i-1][j-1]*c[n-j][m-i])%mod;
                    ans%=mod;
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

H:https://ac.nowcoder.com/acm/contest/885/H

题意:给出多组两个字母,和由它们组成的在原串中的子序列,求出原串。

简单模拟题:处理出每个字母出现的行数

                      原串中0-n-1的位置枚举每0-m-1个字母,并记录每一行遍历到的位置。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5;
int n,m;
int pos[30][15],cnt[15];
struct hang
{
    int now,len;
    string s;
}e[50];
string str,ans;
bool judge(int v)
{
    for(int i=0;i<m-1;i++){
        int id=pos[v][i];
        if(e[id].now>=e[id].len||e[id].s[e[id].now]!=v+'a')
            return false;
    }
    return true;
}
int main()
{
    cin>>n>>m;
    memset(cnt,0,sizeof(cnt));
    memset(pos,0,sizeof(pos));
    for(int i=1;i<=m*(m-1)/2;i++){
        cin>>str>>e[i].len;
        if(e[i].len) cin>>e[i].s;
        char a=str[0],b=str[1];
        e[i].now=0;
        pos[a-'a'][cnt[a-'a']++]=i;
        pos[b-'a'][cnt[b-'a']++]=i;
    }
    for(int i=0;i<n;i++){
        int l=-1;
        for(int j=0;j<m;j++){
            if(judge(j)){
                l=j;break;
            }
        }
        if(l==-1){
            cout<<"-1"<<endl;
            return 0;
        }
        else{
            for(int i=0;i<m-1;i++){
                e[pos[l][i]].now++;
            }
            ans+='a'+l;
        }
    }
    for(int i=1;i<=m*(m-1)/2;i++){
        if(e[i].now!=e[i].len){
            cout<<"-1"<<endl;
            return 0;
        }
    }
    cout<<ans<<endl;
    return 0;
}

I:https://ac.nowcoder.com/acm/contest/885/I

题意:给出一个矩形,三角形的三条边长,求出是否存在这样的三角形。

1. 若一个三角形能摆在一个矩形里,总是能经过平移使得三角形至少有一个顶点和矩形

的顶点重叠,且三角形的顶点仍在矩形里2. 重叠了三角形的某个顶点和矩形的某个顶点后,我们可以把该重叠的点当旋转轴,旋

转三角形,使得三角形有另一个点恰好在矩形的某个边上于是我们可以枚举三角形的哪个顶点和举行的顶点重叠,以及三角形另一个位在矩形边上的 点是哪个,总是能枚举到一个完全落在矩形里面的三角形摆放位置

#include<bits/stdc++.h>
#define esp 1e-8
using namespace std;
struct node {
    double x, y;
} point[3];
double w, h;
int check(double a, double b, double c, int x, int y, int z) {
    point[x].x = 0.0;   //点x定在原点
    point[x].y = 0.0;
//点y定在贴近x轴的一侧
    if(a <= w) {
        point[y].x = a;
        point[y].y = 0.0;
    } else {
        point[y].x = w;
        point[y].y = sqrt(a*a - w*w);
    }
    double jc = acos((a*a + b*b - c*c)/(2*a*b)); //通过余弦公式算出长度为a和长度为b的边的夹角
    jc += atan(point[y].y / point[y].x);
    //算出长度为a的边与x轴的夹角与上一个结果加起来
    // 得出长度为b的边与x轴的夹角
    //已知夹角便可算出第三个点的位置
    point[z].x = cos(jc) * b;
    point[z].y = sin(jc) * b;
    //判断 y点和x点在不在 w和h的范围内
    if(point[z].x >= 0-esp && point[z].x <= w+esp && point[z].y >= 0-esp && point[z].y <= h+esp) {
        printf("%.12f %.12f %.12f %.12f %.12f %.12f\n",
               point[0].x, point[0].y,
               point[1].x, point[1].y,
               point[2].x, point[2].y);
        return 1;
    } 
    else {
        return 0;
    }
}
 
int main() {
    int t;
    double a, b, c;
    scanf("%d", &t);
    while(t--) {
        scanf("%lf %lf %lf %lf %lf", &w, &h, &a, &b, &c);
        if(check(a,b,c,0,1,2)) continue;
        if(check(a,c,b,1,0,2)) continue;
        if(check(b,a,c,0,2,1)) continue;
        if(check(c,a,b,1,2,0)) continue;
        if(check(b,c,a,2,0,1)) continue;
        if(check(c,b,a,2,1,0)) continue;
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值