Educational Codeforces Round 81

C. Obtain The String
题意:给两个字符串s,t选择最少的s的子序列拼接成t
用多个s去匹配t,看能否把t匹配完,这样暴力跑每个字符会t,所以可以进行一点优化,记录s中每个字符后面出现了哪些字符,然后就可以O(1)地进行转移;

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (10007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 1e5 + 5;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
char s[maxn],t[maxn];
int nxt[maxn][30],vis[30];  //nxt[i][j]表示第i位后的j字符的位置,j是字符-'a'后的值
int main()
{
    int T = read();
    while(T--) {
        cin>>s>>t;
        int lens = strlen(s),lent = strlen(t),flag = 0;
        memset(vis,0,sizeof(vis));
        for(int i = 0;i < lent; ++i) vis[t[i] - 'a'] = 1;
        for(int i = 0;i < lens; ++i) vis[s[i] - 'a'] = 0;
        for(int i = 0;i < 26; ++i) if(vis[i]) { printf("-1\n"); flag = 1; break;}
        if(flag) continue;
        for(int i = 0;i < 26; ++i) nxt[lens][i] = -1;
        for(int i = lens - 1;i >= 0; --i) {
            for(int j = 0;j < 26; ++j) nxt[i][j] = nxt[i + 1][j];
            nxt[i][s[i] - 'a'] = i;
        }
        int ans = 1,now = 0;
        for(int i = 0;i < lent; ++i) {
            now = nxt[now][t[i] - 'a'];
            if(now == -1) {  //now后面没有能够和t匹配的,所以重新开始匹配;
                now = 0;i--;ans++;
            }else ++now;
        }
        cout<<ans<<endl;
    }
    return 0;
}

题意:求解gcd(a,m) = gcd(a+x,m)这样的x有多少个( 0≤x<m);
假设gcd(a,m) = p;那么问题就转化为 gcd(a+x,m) = p ->gcd((a + x) / p,m / p) = 1;令l = a / p , r = m / p -> gcd((l + x / p),r) = 1,就是求解[l,l + r)中和r互质的数的个数,拆分成[l,r]和(r,l + r) 两个区间;
∵: gcd(a,b) = gcd(a + bt,b) (其中t为任意整数)令k是区间[1,l)中的任意一个数, gcd(k,r) = gcd(k + r,r) ,k + r ∈ (r,l + r),这表明[1,l - 1]中和r互质的数和(r,l + r)中和r互质的数是相等的;
∵ 我们的答案 = [l,r]满足要求的数 + (r,l + r) 满足要求的数
求[l,r] 等价于 求[1,r]满足要求的数 - [1,l - 1]中满足要求的数,
而[1,l - 1]中满足要求的数 = (r,l + r)中满足要求的数
所以得出结论 我们的答案 = [1,r]满足要求的数,求r的欧拉函数就是了

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (10007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 1e5 + 5;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
ll a,m;
ll gcd(ll a,ll b) {
    return (b == 0 ? a : gcd(b,a%b));
}
ll Euler(ll x) {
    ll res = x;
    for(ll i = 2;i <= sqrt(x); ++i) {
        if(x % i == 0) {
            res -= res / i;
            while(x % i == 0) x/=i;
        }
    }
    if(x > 1) res -= res / x;
    return res;
}
int main()
{
    int T = read();
    while(T--) {
        cin>>a>>m;
        ll p = gcd(a,m);
        ll x = m / p;
        cout<<Euler(x)<<endl;
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值