反省:一開始用前綴積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;
}
思路:字符串前綴和,從小枚舉字母,判斷左右區間出現次數是否相同,相同時即該字母沒有出現過,詳細見代碼。
#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;
}
反省:看到跟樹有關就做題興致不高,缺乏競技精神,就算是樹也是要試一下。
思路:最小路徑和肯定要設置權值小的邊離根比較近,所以先排序,然後用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;
}