您的位置:首页 > 其它

2017.11.03离线赛总结

2017-11-04 16:01 169 查看

excellent ——3802

思路:首先显然可以看出是枚举i个a,得到n-i个b,但组合数只有70,而且还有mod,那么当然要通过逆元+费马小定理来快速幂掉。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define db double
#define INF 0x3f3f3f3f
#define inf 0x7fffffff
#define mcl(a,b) memset(a,b,sizeof(a))
#define Sz(a) sizeof(a)
#define pb push_back

#define N 1000005
#define P 1000000007

int a,b,n;

bool check(int x){
while(x>0){
int y=x%10;
if(y!=a && y!=b)return 0;
x/=10;
}
return 1;
}
struct p40{
int ans;
void dfs(int x,int sum){
if(x==n){
if(check(sum)){
ans++;
if(ans>=P)ans-=P;
}
return;
}
dfs(x+1,sum+a);
dfs(x+1,sum+b);
}
void solve(){
dfs(0,0);
cout<<ans<<endl;
}
}p40;

struct p70{
int ans;
int C[1505][1505];
void Init(){
C[0][0]=1;
REP(i,1,1500){
C[i][0]=1;
REP(j,1,i)(C[i][j]=C[i-1][j-1]+C[i-1][j])%=P;
}
}
void solve(){
Init();
REP(i,0,n){
int x=a*i+b*(n-i);
if(check(x)){
ans+=C
[i];
if(ans>=P)ans-=P;
}
}
cout<<ans<<endl;
}
}p70;
struct p100{
LL Pow(LL x,LL y){
LL res=1;
while(y>0){
if(y&1)(res*=x)%=P;
x=x*x%P;y>>=1;
}
return res;
}
LL fac
;
void solve(){
fac[0]=1;
REP(i,1,n)fac[i]=fac[i-1]*i%P;
LL ans=0;
REP(i,0,n){
int x=a*i+b*(n-i);
if(!check(x))continue;
ans+=fac
*Pow(fac[n-i],P-2)%P*Pow(fac[i],P-2)%P,ans%=P;
}
cout<<ans<<endl;
}
}p100;
int main(){
//  freopen("excellent.in","r",stdin);
//  freopen("excellent.out","w",stdout);
cin>>a>>b>>n;
if(n<=15)p40.solve();
else if(n<=1000)p70.solve();
else p100.solve();
return 0;
}


num ——3803

思路:赤裸裸的dp,也比较好定义的——dp[i][j]表示上一个截点的位置为j,当前的数字串为j+1到i。但这样还不够(只有70),还需要后缀数组优化一下(kmp)。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define db double
#define INF 0x3f3f3f3f
#define inf 0x7fffffff
#define mcl(a,b) memset(a,b,sizeof(a))
#define Sz(a) sizeof(a)
#define pb push_back

#define N 3004
#define P 1000000007

int n;
char s
;
int dp

;
struct P80{
bool Cmp(int x,int y,int len){
while(len && s[x]==s[y])x++,y++,len--;
if(len)return s[x]<s[y];
return 0;
}
void solve(){
int tmp;
if(s[1]!='0')REP(i,1,n)dp[1][i]=1;
REP(i,1,n)REP(j,i,n-1)if((tmp=dp[i][j]) && s[j+1]!='0'){
int len=j-i+1;
if(j+len<=n && Cmp(i,j+1,len))(dp[j+1][j+len]+=tmp)%=P;
REP(k,j+len+1,n)(dp[j+1][k]+=tmp)%=P;
}
int ans=0;
REP(i,1,n)(ans+=dp[i]
)%=P;
cout<<ans<<endl;
}
}p80;
struct p100{
int mark

;
void Init(){
DREP(i,n,1){
DREP(j,n,1){
if(s[i]>s[j])mark[i][j]=i;
else if(s[i]<s[j])mark[i][j]=0;
else mark[i][j]=mark[i+1][j+1];
}
}
}
void solve(){
Init();
REP(i,1,n)dp[1][i]=1;
REP(i,2,n){
if(s[i]=='0')continue;
for(int j=i,k=i-1;j<=n && k;j++,k--){
if(s[k]=='0')continue;
if(mark[i][k] && mark[i][k]<=j)(dp[i][j]+=dp[k][i-1])%=P;
else (dp[i][j+1]+=dp[k][i-1])%=P;
}
REP(j,i+1,n)(dp[i][j]+=dp[i][j-1])%=P;
}
LL ans=0;
REP(i,1,n)(ans+=dp[i]
)%=P;
cout<<ans<<endl;
}
}p100;
int main(){
//  freopen("num.in","r",stdin);
//  freopen("num.out","w",stdout);
cin>>n;
scanf("%s",s+1);
if(n<1000)p80.solve();
else p100.solve();
return 0;
}


tree ——3804

思路:题意十分清晰,简而言之,就是其它点到两个被选定的点的最大距离。

由链的情况——答案应为max(a−1,n−b,mid(b−a>>1))

引发我们思考,将树抽出一条链,也就是树的直径,那么答案同理,即a左边的所有点到a的最大距离,b右边的所有点到b的最大距离,以及a,b之间的所有点到a,b的最小值的最大值。这里两边的点都比较好处理,而中间的点需要再求出直径上a,b之间的点到其子树的每个点的距离,也就是max(min(dis[top]−dis[a],dis[b]−dis[top])+dep[x])

然而实现起来就比较困难了。

1.距离要倍增算,而且还要每个点向上跳和向下跳都要算出来。(蒟蒻我还没来得及写…)

2.也可以线段树来维护。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define LL long long
#define db double
#define INF 0x3f3f3f3f
#define inf 0x7fffffff
#define mcl(a,b) memset(a,b,sizeof(a))
#define Sz(a) sizeof(a)
#define pb push_back
#define lson L,mid,p<<1
#define rson mid+1,R,p<<1|1
#define family tree[p],tree[p<<1],tree[p<<1|1]
#define root 1,n,1

#define N 100000

int n,m;
int A
,B
;
int D
,son
,fa
,top
,sz
;
vector<int>E
;

void dfs1(int x,int f){
sz[x]=1;
D[x]=D[f]+1;
fa[x]=f;
son[x]=0;
REP(i,0,E[x].size()-1){
int y=E[x][i];
if(y==f)continue;
dfs1(y,x);
sz[x]+=sz[y];
if(sz[y]>sz[son[x]])son[x]=y;
}
}
void dfs2(int x,int tp){
top[x]=tp;
if(son[x])dfs2(son[x],tp);
REP(i,0,E[x].size()-1){
int y=E[x][i];
if(y==fa[x] || y==son[x])continue;
dfs2(y,y);
}
}
int Lca(int a,int b){
while(top[a]!=top[b]){
if(D[top[a]]<D[top[b]])swap(a,b);
a=fa[top[a]];
}
return D[a]<D[b]?a:b;
}

struct plist{
int Index,ID[100012];
bool check(){
REP(i,1,n)if(E[i].size()>2)return 0;
return 1;
}
void dfs(int x,int f){
ID[x]=++Index;
REP(i,0,E[x].size()-1){
int V=E[x][i];
if(V==f) continue;
dfs(V,x);
}
}
void solve(){
int s=0;
for(int i=1;i<=n;i++)if(E[i].size()==1){s=i;break;}
Index=0;
dfs(s,s);
REP(i,1,m){
int a,b;
int ans=0;
a=ID[A[i]],b=ID[B[i]];
if(a>b) swap(a,b);
ans=max(a-1,n-b);
ans=max(ans,(b-a)>>1);
printf("%d\n",ans);
}
}
}p_list;
struct p30{
void solve(){
dfs1(1,0);
dfs2(1,1);
REP(i,1,m){
int a=A[i],b=B[i];
int ans=0;
REP(j,1,n){
int lca1=Lca(a,j),lca2=Lca(b,j);
int s1=D[a]+D[j]-D[lca1]*2;
int s2=D[b]+D[j]-D[lca2]*2;
ans=max(ans,min(s1,s2));
}
printf("%d\n",ans);
}
}
}p30;

int Mxval
;
struct p100{
int d,Dx,Rx,s;
int Id
,dis
,is_D
,Link
;
struct Tree{
struct node{
int L,R,mx;
}tree[N<<2];
void build(int L,int R,int p,int x){
tree[p].L=L,tree[p].R=R;
if(L==R){
tree[p].mx=Mxval[L]+L*x;
return;
}
int mid=(L+R)>>1;
build(lson,x),build(rson,x);
tree[p].mx=max(tree[p<<1].mx,tree[p<<1|1].mx);
}
int query(int L,int R,int p){
if(tree[p].L==L && tree[p].R==R)return tree[p].mx;
int mid=(tree[p].L+tree[p].R)>>1;
if(R<=mid)return query(L,R,p<<1);
else if(L>mid)return query(L,R,p<<1|1);
else return max(query(lson),query(rson));
}
}Tree[2];
void dfs(int x,int f,int cost){
if(cost>d)d=cost,Dx=x;
fa[x]=f;
REP(i,0,E[x].size()-1){
int y=E[x][i];
if(y==f)continue;
dfs(y,x,cost+1);
}
}
int k;
void Dfs(int x,int f,int cost){
Id[x]=k;
dis[x]=cost;
if(cost>Mxval[k])Mxval[k]=cost;
REP(i,0,E[x].size()-1){
int y=E[x][i];
if(y==f || is_D[y])continue;
Dfs(y,x,cost+1);
}
}
void Setid(){
int a=Dx;
while(a!=Rx){
is_D[a]=1;
Link[++s]=a;
a=fa[a];
}
Link[++s]=a;
is_D[a]=1;
REP(i,1,s){
k=i;
Dfs(Link[i],0,0);
}
}
void solve(){
d=-1;
dfs(1,0,0);
Rx=Dx,d=-1;
dfs(Rx,0,0);
Setid();
Tree[0].build(1,s,1,1);
Tree[1].build(1,s,1,-1);

REP(i,1,m){
int a=A[i],b=B[i];
if(Id[b]<Id[a])swap(a,b);
int x=(Id[a]+Id[b]+dis[b]-dis[a])/2;
int ans=0;
if(Id[a]==Id[b]){
ans=min(dis[a],dis[b])+Id[a]-1;
ans=max(s+min(dis[a],dis[b])-Id[a],ans);
printf("%d\n",ans);
continue;
}else {
int tmp1=min(dis[a]+Id[a]-1,dis[b]+Id[b]-1);
int tmp2=min(dis[a]+s-Id[a],dis[b]+s-Id[b]);
ans=max(tmp1,tmp2);
}
if(Id[a]<min(Id[b],x))ans=max(ans,Tree[0].query(Id[a]+1,min(Id[b],x),1)-Id[a]+dis[a]);
if(max(Id[a],x+1)<Id[b])ans=max(ans,Tree[1].query(max(Id[a],x+1),Id[b]-1,1)+Id[b]+dis[b]);
printf("%d\n",ans);
}
}
}p100;
int main(){
//  freopen("tree.in","r",stdin);
//  freopen("tree.out","w",stdout);
cin>>n;
REP(i,1,n-1){
int a,b;
scanf("%d%d",&a,&b);
E[a].pb(b);E[b].pb(a);
}
cin>>m;
REP(i,1,m)scanf("%d%d",&A[i],&B[i]);
//  if(n<=2000)p30.solve();
//  else if(p_list.check())p_list.solve();
//  else p100.solve();
p100.solve();
return 0;
}


小结:今天考得不是很好,第1题逆元没想到,第3题链写错了…(代码功底还要加强呀!)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: