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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章