题意
给你一个小写字母的字符串,问这个祖字符串中每个字母是否只出现了一次,且所有出现的字母连续。
多组询问。
解法
,瞎暴力都能过。。。
暴力大法好!
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define MAXN 110 using namespace std; int len,num[26]; char str[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } bool solve(){ for(int i=1;i<=len;i++)num[str[i]-'a']++; for(int i=0;i<=25;i++)if(num[i]>1)return false; int l=0,r; while(num[l]==0&&l<=25)l++; r=l; while(num[r]==1&&r<=25)r++; if(r>25)return true; l=r; while(num[l]==0&&l<=25)l++; if(l<=25)return false; else return true; } void init(){ scanf("%s",str+1); len=strlen(str+1); memset(num,0,sizeof(num)); } int main(){ int t=read(); while(t--){ init(); if(solve())printf("Yes\n"); else printf("No\n"); } return 0; }
题意
给你个数字的数列,要求分成若干段,每段中奇数和偶数的个数相同,每次分割的代价是分割两侧数字的差的绝对值。
求在代价不超过某个预算值且代价花费最大的情况下,最多能分多少段。
解法
显然我们可以先把所有能分割的位置搞出来,然后按照代价丢进一个小根堆里,每次取出堆顶即可。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cmath> #include<queue> #include<vector> #define MAXN 110 using namespace std; priority_queue<int,vector<int>,greater<int>> q; int n,m,ans=0,val[MAXN],num[MAXN]; char tp[100000],*p1=tp,*p2=tp; inline char get_char(){ return p1==p2&&(p2=(p1=tp)+fread(tp,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=get_char();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=get_char();} return date*w; } void work(){ while(!q.empty()){ int x=q.top(); q.pop(); if(x>m)break; m-=x; ans++; } printf("%d\n",ans); } void init(){ n=read();m=read(); num[0]=0; for(int i=1;i<=n;i++){ val[i]=read(); if(val[i]&1)num[i]=num[i-1]+1; else num[i]=num[i-1]-1; if(i>=2&&num[i-1]==0)q.push(abs(val[i-1]-val[i])); } } int main(){ init(); work(); return 0; }
题意
给一颗个点的根为(首都)的树,把个点选为工业城市,剩下的为旅游城市,求所有工业城市到首都的路径上旅游城市的个数的总和。
解法
首先首都肯定是旅游城市。
其次旅游城市一定要尽可能地靠近首都,这样才更可能被重复计数。
然后把问题转化一下:如果所有的城市都是工业城市,那么我们只要选出个旅游城市即可。
这和原问题不是差不多么?!
但是这样我们就能考虑假如把一个城市设为旅游城市,对答案的贡献是多少。
很容易发现这个贡献就是。
所以我们把每个点按照排个序,从大到小选个即可。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 200010 using namespace std; int n,m,c=1; int head[MAXN],deep[MAXN],size[MAXN],pos[MAXN]; long long ans=0; struct Tree{ int next,to; }a[MAXN<<1]; char tp[100000],*p1=tp,*p2=tp; inline char get_char(){ return p1==p2&&(p2=(p1=tp)+fread(tp,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=get_char();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=get_char();} return date*w; } inline bool cmp(const int &x,const int &y){ return size[x]-deep[x]>size[y]-deep[y]; } void add_edge(int x,int y){ a[c].to=y;a[c].next=head[x];head[x]=c++; a[c].to=x;a[c].next=head[y];head[y]=c++; } void dfs(int rt){ size[rt]=1; for(int i=head[rt];i;i=a[i].next){ int will=a[i].to; if(!deep[will]){ deep[will]=deep[rt]+1; dfs(will); size[rt]+=size[will]; } } } void work(){ for(int i=1;i<=n;i++)pos[i]=i; sort(pos+1,pos+n+1,cmp); for(int i=1;i<=n-m;i++)ans+=1LL*(size[pos[i]]-deep[pos[i]]); printf("%lld\n",ans); } void init(){ n=read();m=read(); for(int i=1,x,y;i<n;i++){ x=read();y=read(); add_edge(x,y); } deep[1]=1; dfs(1); } int main(){ init(); work(); return 0; }
题意
有一个长度为,各个数字值域为的全排列序列,给出序列,,请求出序列。保证有解。
解法
对于一开始序列最后一个数,最后一个数的值必为。
但是对于之前的数,它有可能大于,这使得这个位置上的值不是,而是少了一个。
所以我们需要从后往前推,并且动态维护前缀和。
前缀和?树状数组,请开始你的表演。
可以用树状数组维护的。
找最后那个未知的数在外面套一个二分就行了。
复杂度,树状数组常数极小,还是能轻松过的。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 200010 using namespace std; int n,ans[MAXN]; long long val[MAXN],sum[MAXN]; char tp[100000],*p1=tp,*p2=tp; inline char get_char(){ return p1==p2&&(p2=(p1=tp)+fread(tp,1,100000,stdin),p1==p2)?EOF:*p1++; } inline long long read(){ long long date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=get_char();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=get_char();} return date*w; } inline int lowbit(int x){return x&(-x);} inline void update(int x,int v){for(;x<=n;x+=lowbit(x))sum[x]+=v;} inline long long query(int x){long long s=0;for(;x;x-=lowbit(x))s+=sum[x];return s;} void work(){ for(int i=n,l,r,mid,s;i>=1;i--){ l=1;r=n;s=0; while(l<=r){ mid=l+r>>1; if(query(mid-1)<=val[i]){ s=mid; l=mid+1; } else r=mid-1; } update(s,-s); ans[i]=s; } for(int i=1;i<=n;i++)printf("%d ",ans[i]); printf("\n"); } void init(){ n=read(); for(int i=1;i<=n;i++){ val[i]=read(); update(i,i); } } int main(){ init(); work(); return 0; }
题意
给你一堆素数,求这些数的乘积的所有因子的乘积模的值。
解法
因为给出的都是素数,所以我们不用质因数分解了,直接排序去重,统计每个数出现多少次即可。
对于每个数,我们知道它出现了次,可以取它的次方。
而其他数的所有取法有种。
所以我们设:
那么对答案的贡献就是:
最终答案就是:
但是那个幂次太大了,也无能为力啊。。。
这个时候就要拿出费马小定理了:
当时,。
所以:
这样就完成了。
一开始有个地方没开直接,药丸。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #define MAXN 200010 #define MOD 1000000007LL using namespace std; int n,val[MAXN],num[MAXN]; long long ans=1,f[MAXN],g[MAXN],s[MAXN]; char tp[100000],*p1=tp,*p2=tp; inline char get_char(){ return p1==p2&&(p2=(p1=tp)+fread(tp,1,100000,stdin),p1==p2)?EOF:*p1++; } inline long long read(){ long long date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=get_char();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=get_char();} return date*w; } long long mexp(long long a,long long b,long long c){ long long s=1; while(b){ if(b&1)s=s*a%c; a=a*a%c; b>>=1; } return s; } void work(){ f[0]=1; for(int i=1;i<=n;i++)f[i]=f[i-1]*(num[val[i]]+1)%(MOD-1); g[n+1]=1; for(int i=n;i>=1;i--)g[i]=g[i+1]*(num[val[i]]+1)%(MOD-1); for(int i=1;i<=n;i++){ long long k=f[i-1]%(MOD-1)*g[i+1]%(MOD-1)*(1LL*(1LL*num[val[i]]*(num[val[i]]+1)/2)%(MOD-1))%(MOD-1); ans=ans*mexp(val[i],k,MOD)%MOD; } printf("%lld\n",ans); } void init(){ memset(num,0,sizeof(num)); n=read(); for(int i=1;i<=n;i++){ val[i]=read(); num[val[i]]++; } sort(val+1,val+n+1); n=unique(val+1,val+n+1)-val-1; } int main(){ init(); work(); return 0; }