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 南京赛区网络预赛 做题记录的主要内容,如果未能解决你的问题,请参考以下文章

ACM-ICPC 2018 南京赛区网络预赛 E题

ACM-ICPC 2018 南京赛区网络预赛 Lpl and Energy-saving Lamps 线段树

ACM-ICPC 2018 南京赛区网络预赛

ACM-ICPC 2018 南京赛区网络预赛(更新中)

ACM-ICPC 2018 南京赛区网络预赛 J.Sum

ACM-ICPC 2018 南京赛区网络预赛 - C GDY (模拟)