ACM-ICPC 2018 南京赛区网络预赛 做题记录
Posted uuzlove
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ACM-ICPC 2018 南京赛区网络预赛 做题记录相关的知识,希望对你有一定的参考价值。
比赛的时候被J题卡常然后B题自闭最后G题没调完
5题gg
现在补题进度:6/12
A.
题解:
高考数学题,裂项完之后答案就是n!-1
(n!)%n=0,所以就是n-1
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int T; 5 ll n; 6 int main() 7 { 8 cin>>T; 9 while(T--) 10 { 11 cin>>n; 12 cout<<n-1<<endl; 13 } 14 return 0; 15 }
E.
题解:
状压DP入门题
1 #include<bits/stdc++.h> 2 #define inf 1e16 3 #define ll long long 4 #define maxn 2000005 5 using namespace std; 6 ll a[22],b[22]; 7 int pre[22]; 8 int n; 9 ll dp[maxn]; 10 int main() 11 { 12 scanf("%d",&n); 13 for(int i=0;i<n;++i) 14 { 15 cin>>a[i]>>b[i]; 16 int s,x; 17 scanf("%d",&s); 18 while(s--) 19 { 20 scanf("%d",&x);x--; 21 pre[i]|=(1<<x); 22 } 23 } 24 int fullset=(1<<n)-1; 25 for(int S=1;S<=fullset;++S)dp[S]=-inf; 26 for(int S=0;S<=fullset;++S) 27 { 28 int t=1; 29 for(int i=0;i<n;++i)if(S&(1<<i))t++; 30 for(int i=0;i<n;++i)if(((S&pre[i])==pre[i])&&(!(S&(1<<i)))) 31 { 32 dp[S|(1<<i)]=max(dp[S|(1<<i)],dp[S]+a[i]*t+b[i]); 33 } 34 } 35 ll ans=0; 36 for(int S=0;S<=fullset;++S)ans=max(ans,dp[S]); 37 cout<<ans<<endl; 38 return 0; 39 }
G.
题解:
将询问离线处理,然后线段树维护一下最小值,模拟一下每次的过程
左边如果有<=tot的就向左跑,否则向右跑
然后这样的话每个元素最多被修改一次,O(nlogn)
1 #include<bits/stdc++.h> 2 #define inf 1000000007 3 #define maxn 100005 4 using namespace std; 5 int n,m,q,tot; 6 int a[maxn]; 7 int minv[maxn<<2]; 8 int Ans1[maxn],Ans2[maxn]; 9 void pushup(int rt) 10 { 11 minv[rt]=min(minv[rt<<1],minv[rt<<1|1]); 12 } 13 void build(int rt,int l,int r) 14 { 15 int mid=(l+r)>>1; 16 if(l==r) 17 { 18 minv[rt]=a[l]; 19 return; 20 } 21 build(rt<<1,l,mid);build(rt<<1|1,mid+1,r); 22 pushup(rt); 23 } 24 void get(int rt,int l,int r) 25 { 26 int mid=(l+r)>>1; 27 if(l==r) 28 { 29 tot-=minv[rt];minv[rt]=inf; 30 return; 31 } 32 if(minv[rt<<1]<=tot)get(rt<<1,l,mid); 33 else get(rt<<1|1,mid+1,r); 34 pushup(rt); 35 } 36 int main() 37 { 38 scanf("%d%d",&n,&m); 39 for(int i=1;i<=n;++i)scanf("%d",&a[i]); 40 build(1,1,n); 41 int res=0; 42 for(int i=1;i<=100000;++i) 43 { 44 tot+=m; 45 int t=minv[1]; 46 while(tot>=t) 47 { 48 get(1,1,n); 49 res++; 50 t=minv[1]; 51 } 52 Ans1[i]=res,Ans2[i]=tot; 53 } 54 scanf("%d",&q); 55 while(q--) 56 { 57 int x;scanf("%d",&x); 58 printf("%d %d ",Ans1[x],Ans2[x]); 59 } 60 return 0; 61 }
I.
题解:
回文树,记录每个本质不同的回文串出现的其中一个位置
然后求一串数字的值就很简单:类似字符串hash的方法就行了
1 #include<bits/stdc++.h> 2 #define maxn 2000005 3 #define ll long long 4 using namespace std; 5 const ll mod=1000000007; 6 int N; 7 int lpos[maxn],rpos[maxn],c; 8 char str[maxn]; 9 ll sum[maxn],xp[maxn]; 10 ll get(int l,int r) 11 { 12 ll x=sum[r]-sum[l-1]*xp[r-l+1]%mod; 13 x=(x%mod+mod)%mod; 14 return x; 15 } 16 struct PAM 17 { 18 int ch[maxn][10],fail[maxn],len[maxn],cnt[maxn],num[maxn],s[maxn]; 19 int n,tot,last; 20 int newnode(int x){len[tot]=x;return tot++;} 21 void init() 22 { 23 newnode(0);newnode(-1); 24 fail[0]=1;fail[1]=1; 25 n=last=0;s[n]=-1; 26 } 27 int getfail(int x){while(s[n]!=s[n-len[x]-1])x=fail[x];return x;} 28 void add(int x,int pos) 29 { 30 s[++n]=x; 31 int t=getfail(last); 32 if(!ch[t][x]) 33 { 34 int now=newnode(len[t]+2); 35 fail[now]=ch[getfail(fail[t])][x]; 36 ch[t][x]=now; 37 num[now]=num[fail[now]]+1; 38 rpos[now]=pos;lpos[now]=pos-len[now]+1; 39 } 40 last=ch[t][x]; 41 cnt[last]++; 42 } 43 void build(char *s) 44 { 45 init(); 46 for(int i=1;i<=N;++i)add(s[i]-‘0‘,i); 47 for(int i=tot;i;--i)cnt[fail[i]]+=cnt[i]; 48 } 49 void count() 50 { 51 ll ans=0; 52 for(int i=1;i<=tot;++i)if(rpos[i]) 53 { 54 ans+=get(lpos[i],rpos[i])%mod; 55 ans%=mod; 56 } 57 cout<<ans<<endl; 58 } 59 }pam; 60 int main() 61 { 62 scanf("%s",str+1); 63 N=strlen(str+1); 64 for(int i=1;i<=N;++i)sum[i]=sum[i-1]*10+str[i]-‘0‘,sum[i]%=mod; 65 xp[0]=1; 66 for(int i=1;i<=N;++i)xp[i]=xp[i-1]*10%mod; 67 pam.build(str); 68 pam.count(); 69 return 0; 70 }
J.
题解:
先用线性筛处理每个数有多少个质因数(拖一个求约数个数的板子改一通就好)
然后枚举素数p,
若x=k*p^3(k为整数),那么不可能分成x=ab使每个只有一个因子,f(x)=0
若x=k*p^2(k不为p的倍数),那么一定是a,b一边一个
然后我们记录一个数有多少平方质因子,质因数个数减掉平方质因子个数就是单独的质因子个数
这些质因子是可以随便选的,f(x)=pow(2,t)
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define maxn 20000005 4 using namespace std; 5 int T,n; 6 bool vis[maxn]; 7 int prime[maxn],d[maxn],num[maxn]; 8 int cnt; 9 void getprime() 10 { 11 cnt=0; 12 for(int i=2;i<=maxn-5;++i) 13 { 14 if(!vis[i]) 15 { 16 prime[++cnt]=i; 17 num[i]=1; 18 d[i]=1; 19 } 20 for(int j=1;j<=cnt&&i*prime[j]<=maxn-5;++j) 21 { 22 vis[i*prime[j]]=1; 23 if (!(i%prime[j])) 24 { 25 num[i*prime[j]]=num[i]+1; 26 d[i*prime[j]]=d[i]; 27 break; 28 } 29 d[i*prime[j]]=d[i]+1; 30 num[i*prime[j]]=1; 31 } 32 } 33 } 34 int has[maxn],f[maxn]; 35 void prepare() 36 { 37 for(int i=1;i<=cnt;++i) 38 { 39 ll x=prime[i]*prime[i]; 40 if(x>maxn-5)break; 41 x*=prime[i]; 42 if(x>maxn-5)break; 43 for(int j=x;j<=maxn-5;j+=x)has[j]=-1; 44 } 45 for(int i=1;i<=cnt;++i) 46 { 47 ll x=prime[i]*prime[i]; 48 if(x>maxn-5)break; 49 for(int j=x;j<=maxn-5;j+=x)if(has[j]!=-1)has[j]++; 50 } 51 for(int i=1;i<=maxn-5;++i)if(has[i]!=-1) 52 { 53 int t=d[i]-has[i]; 54 f[i]=(1<<t); 55 } 56 for(int i=1;i<=maxn-5;++i)f[i]+=f[i-1]; 57 } 58 int main() 59 { 60 scanf("%d",&T); 61 getprime(); 62 prepare(); 63 while(T--) 64 { 65 scanf("%d",&n); 66 cout<<f[n]<<endl; 67 } 68 return 0; 69 }
L.
题解:
分层图最短路裸题
1 #include<bits/stdc++.h> 2 #define ll long long 3 #define inf 1e16 4 #define maxn 100005 5 using namespace std; 6 int T,n,m,k; 7 int head[maxn],p; 8 struct edge 9 { 10 int to,next,w; 11 }e[maxn<<1]; 12 void addedge(int u,int v,int w) 13 { 14 e[++p].to=v;e[p].w=w;e[p].next=head[u];head[u]=p; 15 } 16 struct node 17 { 18 int x,lv,dis; 19 node(int x=0,int lv=0,int dis=0):x(x),lv(lv),dis(dis){} 20 }; 21 bool operator < (node a,node b) 22 { 23 return a.dis>b.dis; 24 } 25 ll dis[maxn][11],used[maxn][12]; 26 ll dij(int s,int t) 27 { 28 for(int i=1;i<=n;++i) 29 for(int j=0;j<=k;++j)dis[i][j]=inf,used[i][j]=0; 30 priority_queue<node> q;q.push(node(s,0)); 31 dis[s][0]=0; 32 while(!q.empty()) 33 { 34 node u=q.top();q.pop(); 35 int x=u.x,lv=u.lv; 36 if(used[x][lv])continue; 37 used[x][lv]=1; 38 for(int i=head[x];i;i=e[i].next) 39 { 40 int v=e[i].to,w=e[i].w; 41 if(dis[v][lv]>dis[x][lv]+w) 42 { 43 dis[v][lv]=dis[x][lv]+w; 44 q.push(node(v,lv,dis[v][lv])); 45 } 46 if(lv<k&&dis[v][lv+1]>dis[x][lv]) 47 { 48 dis[v][lv+1]=dis[x][lv]; 49 q.push(node(v,lv+1,dis[v][lv+1])); 50 } 51 } 52 } 53 ll ans=inf; 54 for(int j=0;j<=k;j++)ans=min(ans,dis[t][j]); 55 return ans; 56 } 57 int main() 58 { 59 scanf("%d",&T); 60 while(T--) 61 { 62 scanf("%d%d%d",&n,&m,&k); 63 memset(head,0,sizeof(head));p=0; 64 for(int u,v,w,i=1;i<=m;++i) 65 { 66 scanf("%d%d%d",&u,&v,&w); 67 addedge(u,v,w); 68 } 69 cout<<dij(1,n)<<endl; 70 } 71 return 0; 72 }
以上是关于ACM-ICPC 2018 南京赛区网络预赛 做题记录的主要内容,如果未能解决你的问题,请参考以下文章