ATP学姐的模拟赛

  ATPの水题大赛

  声明:不是我觉得这题水,这就是本场模拟赛的名称。

  T1:求所有的$n$位数中有几个数满足:每一位要么是$A$要么是$B$,并且这个$n$位数的每一位加起来是$A$或$B$的倍数。

  $n<=100000,0<A,B<=9$且$A$与$B$不相等

  因为昨天刚讲了数位$dp$,理所当然的就往那方面去想了.其实用组合数学也可以做,而且还比较简短.

  用$f[i][j][k]$表示目前填到第$i$位,对$a$取模余数为$j$,对$b$取模余数为$k$的方案数.滚动数组,空间可以压得非常小.

  
 1 # include <cstdio>
 2 # include <iostream>
 3 # include <cstring>
 4 # include <string>
 5 # define R register int
 6 # define mod 1000000007
 7 
 8 using namespace std;
 9 
10 const int maxn=100005;
11 int dp[3][10][10];
12 int a,b,n,ans,no,nex;
13 
14 inline int ad (int a,int b) { a=a+b; if(a>=mod) a-=mod; return a; }
15 
16 int solve ()
17 {
18     dp[0][0][0]=1;
19     for (R i=0;i<n;++i)
20     {
21         no=i&1;
22         nex=no^1;
23         memset(dp[nex],0,sizeof(dp[nex]));
24         for (R m1=0;m1<a;++m1)
25             for (R m2=0;m2<b;++m2)
26             {
27                 if(!dp[no][m1][m2]) continue;
28                 dp[nex][m1][(m2+a)%b]=ad(dp[no][m1][m2],dp[nex][m1][(m2+a)%b]);
29                 dp[nex][(m1+b)%a][m2]=ad(dp[no][m1][m2],dp[nex][(m1+b)%a][m2]);
30             }
31     }
32     int ans=0;
33     for (R m1=0;m1<a;++m1)
34         for (R m2=0;m2<b;++m2)
35             if(m1==0||m2==0) ans=ad(ans,dp[n&1][m1][m2]);
36     return ans;
37 }
38 
39 int main()
40 {
41     scanf("%d%d%d",&n,&a,&b);
42     printf("%d",solve());
43     return 0;
44 }
T1

 

  T2:求逆序对数量*360。没了。 

  
 1 # include <cstdio>
 2 # include <iostream>
 3 # include <cstring>
 4 # include <string>
 5 # include <algorithm>
 6 # define R register int
 7 # define lowbit(i) (i&(-i))
 8 # define mod 1000000007
 9 
10 using namespace std;
11 
12 const int maxn=500005;
13 struct nod
14 {
15     int key,val;
16 }a[maxn];
17 int n,v[maxn];
18 int t[maxn],ans,cnt;
19 
20 bool cmp (nod a,nod b) { return a.val<b.val; }
21 
22 void add (int pos,int val)
23 {
24     for (R i=pos;i<=cnt;i+=lowbit(i)) t[i]+=val;
25 }
26 
27 int ask (int pos)
28 {
29     int ans=0;
30     for (R i=pos;i;i-=lowbit(i)) ans+=t[i];
31     return ans;     
32 }
33 
34 int main()
35 {
36     scanf("%d",&n);
37     for (R i=1;i<=n;++i)
38         scanf("%d",&a[i].val),a[i].key=i;
39     sort(a+1,a+1+n,cmp);
40     a[0].val=a[1].val+1;
41     for (R i=1;i<=n;++i)
42     {
43         if(a[i].val!=a[i-1].val) ++cnt;
44         v[ a[i].key ]=cnt;
45     }
46     for (R i=1;i<=n;++i)
47     {
48         ans+=ask(cnt)-ask(v[i]);
49         if(ans>=mod) ans-=mod;
50         add(v[i],1);    
51     }
52     ans=(long long)ans*360%mod;
53     printf("%d",ans);
54     return 0;
55 }
T2

 

  T3:给定一棵正边权的树,求离每个点最远的点有多远;

  有一个定理:离每个点最远的点必然是直径端点上的一点,不过...我不是这么做的。

  以任意点为端点的最长路要么在它的子树里面,要么是从父亲走过来的,经典的$up and down$题目.注意,父亲的最长路有可能本来就是从自己这里走过去的,再用父亲来更新就会走重复的路径了.那怎么办呢?再记录一条次长路径即可,细节什么的...自己想吧。 

  
 1 # include <cstdio>
 2 # include <iostream>
 3 # include <cstring>
 4 # include <string>
 5 # define R register int
 6 
 7 using namespace std;
 8 
 9 const int maxn=1000006;
10 int n,h,x,y,co,firs[maxn],dep[maxn],m1[maxn],m2[maxn];
11 struct edge
12 {
13     int too,nex,co;
14 }g[maxn<<1];
15 
16 int read()
17 {
18     int x=0,f=1;
19     char c=getchar();
20     while (!isdigit(c)) { if(c=='-') f=-f; c=getchar(); }
21     while (isdigit(c)) { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }
22     return x*f;
23 }
24 
25 void add (int x,int y,int co)
26 {
27     g[++h].too=y;
28     g[h].co=co;
29     g[h].nex=firs[x];
30     firs[x]=h;
31 }
32 
33 void upp (int x)
34 {
35     int j,len;
36     for (R i=firs[x];i;i=g[i].nex)
37     {
38         j=g[i].too;
39         if(dep[j]) continue;
40         dep[j]=dep[x]+1;
41         upp(j);
42         len=m1[j]+g[i].co;
43         if(len>m1[x]) m2[x]=m1[x],m1[x]=len;
44         else if(len==m1[x]) m2[x]=len;
45         else m2[x]=max(m2[x],len);
46     }
47 }
48 
49 void dowwn (int x)
50 {
51     int j,len;
52     for (R i=firs[x];i;i=g[i].nex)
53     {
54         j=g[i].too;
55         if(dep[j]<dep[x]) continue;
56         len=m1[x];
57         if(len==m1[j]+g[i].co) len=m2[x];
58         len+=g[i].co;
59         if(len>m1[j]) m1[j]=len;
60         else if(len==m1[j]) m2[j]=len;
61         else m2[j]=max(m2[j],len);
62         dowwn(j);
63     }
64 }
65 
66 int main()
67 {
68     n=read();
69     for (R i=1;i<n;++i)
70     {
71         x=read(),y=read(),co=read();
72         add(x,y,co);
73         add(y,x,co);
74     }
75     dep[1]=1;
76     upp(1);
77     dowwn(1);
78     for (R i=1;i<n;++i)
79         printf("%d ",m1[i]);
80     printf("%d",m1[n]);
81     return 0;
82 }
T3

 

  T4:带修改动态逆序对。

  $n$为序列长度,$m$为修改次数.

  

  这题好啊,不用写代码,只需要写一个做法的$txt$,学姐看做法给分qwq.正好是只会说不会写.

  

  这个做法竟然被给了满分QAQ

  ---shzr

posted @ 2018-10-03 17:24  shzr  阅读(220)  评论(0编辑  收藏  举报