11.9 小总结

1.口算训练

反省:一开始用前缀积c++交了一发re,发现不能用py提交,python语法,尝试百度了java的大整数语法又交了一发TLE,其实这道题是用唯一分解定理,上上星期一场div2的第D题也是唯一分解定理,占着做3补1的心理没补,现在有点惭愧,很多知识不学就是真的不会。

思路:把各个数字分解,然后把d分解,在区间中查询对应素数出现的次数是否足够,详细见代码。

#include<bits/stdc++.h>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}

const int manx=1e5+5;;

vector<int>a[manx];

int main()
{
    ll p=read(),x;
    while(p--)
    {
        for(int i=1;i<manx;i++) a[i].clear(); // 初始化
        ll n=read(),m=read();
        for(int i=1;i<=n;i++){
            x=read();
            for(int j=2;j*j<=x;j++)
                while(x%j==0)
                    a[j].push_back(i),x/=j;  //存这个素数存在的下标,出现个数为可分解的次数
            if(x>1) a[x].push_back(i); //如果x是素数,存入下标
        }
        while(m--)
        {
            ll l=read(),r=read(),d=read(),flag=1;
            for(int i=2;i*i<=d;i++)
            {
                int ans=0; //ans统计素数p的幂
                while(d%i==0) ans++,d/=i;
                if(ans){  //t为查询到l到r的区间中i出现次数
                    int t=upper_bound(a[i].begin(),a[i].end(),r)-lower_bound(a[i].begin(),a[i].end(),l);
                    if(t<ans){  //出现次数一定要比ans大,不然无法整除d
                        flag=0;
                        break;
                    }
                }
            }
            if(d>1) {  //如果d为素数,那么只需要出现一次即可
                int t=upper_bound(a[d].begin(),a[d].end(),r)-lower_bound(a[d].begin(),a[d].end(),l);
                if(t<1) flag=0;
            }
            if(flag) put1();
            else put2();
        }
    }
    return 0;
}

2.子串查询

思路:字符串前缀和,从小枚举字母,判断左右区间出现次数是否相同,相同时即该字母没有出现过,详细见代码。

#include<bits/stdc++.h>
#define ll long long
#define R register int
#define inf 0x3f3f3f3f
#define mod 1000000007;
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}

const int manx=1e5+5;;

int a[manx][30];
char s[manx];

int main()
{
    ll p=read(),x=1;
    while(p--)
    {
        memset(a,0,sizeof(a));
        ll n=read(),m=read();
        scanf("%s",s+1);
        for(int i=1;i<=n;i++)
        {
            a[i][s[i]-'A']++;  //字母出现次数 一维是出现的下标,二维是字母
            for(int j=0;j<26;j++)
                a[i+1][j]=a[i][j]; //累加前面出现的次数
        }
        printf("Case #%lld:\n",x++);
        while(m--)
        {
            ll l=read(),r=read();
            for(int i=0;i<26;i++)
                if(a[l-1][i]!=a[r][i]) 
       //如果左区间前一个区间跟右区间出现次数相同,即该字母没有出现过
                {
                    cout<<a[r][i]-a[l-1][i]<<endl;
                    break;
                }
        }
    }
    return 0;
}

3.Build Tree

反省:看到跟树有关就做题兴致不高,缺乏竞技精神,就算是树也是要试一下。
思路:最小路径和肯定要设置权值小的边离根比较近,所以先排序,然后用b数组维护每层的成本(边权和),每一层可由上一层的边权和*n,再按边权大小累加本层的成本,最后每层叠加求和取模即可。

#include<bits/stdc++.h>
#define ll long long
#define R register ll
#define inf 0x3f3f3f3f
#define mod 1000000007;
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("Yes") ;}
void put2(){ puts("No") ;}

const ll manx=2e5+5;;
ll k,m,n,p;
ll a[manx],b[manx]; //a是边的集合  b是第i个间隔层的成本
int main()
{
    while(scanf("%lld%lld%lld%lld",&k,&m,&n,&p)!=EOF){  //hdu多组输入
      //  k=read(),m=read(),n=read(),p=read();
       memset(a,0,sizeof(a));  //初始化 
       memset(b,0,sizeof(b));
        for(ll i=1;i<=k;i++){
            a[i]=read();   //这里不能取模,取模的话会影响后面的计算,wa点1
        }
        sort(a+1,a+1+k);
        ll index=1,res=n;
        m--; //这里减一是为了算层数之间的间隔,wa点2
        for(ll i=1;i<=m;i++){  //遍历每个间隔
            b[i]=(b[i-1]*n)%p;  //上一层的成本* 开叉数
            for(ll j=1;j<=res;j++)   // 每层的分支数
                b[i]=(b[i]+a[index++])%p; //叠加
            res*=n; //每层叉出n倍的节点
        }
        ll ans=0;
        for(ll i=1;i<=m;i++) 
            ans=(ans+b[i])%p; 
        cout<<ans<<endl;
    }
    return 0;
}
发布了50 篇原创文章 · 获赞 15 · 访问量 4244

猜你喜欢

转载自blog.csdn.net/JiangHxin/article/details/102992392