20190807模拟01

还会有02啊

糟心

T1 老司机的压缩包

传送门

老司机的压缩包

zip.cpp/.c/.pas

题目描述:

老司机最近得到了一个奇怪的压缩包,听说里面有十分厉害的东西呢!

但是这个压缩包有一个奇怪的密码设定;

首先有这个压缩包有一个数字n

每次压缩包会给出一个数字[0,n-1]区间的整数,要求老司机回答这个数在mod n下的逆元是多少,如果逆元不存在则视为0即可;

老司机觉得这太简单了,但是因为n很大,老司机并不愿意一个一个输入进去;

所以老司机决定将[0,n-1]所有逆元的和输进去,这样也许就直接可以打开了呢;

然而老司机并不会做这个问题,所以就交给你了!

如果你的回答让老司机满意的话,他也许也会给你一个压缩包哦;

输入(zip.in)

第一行一个整数T,表示有T组测试数据;

然后T行,每行有一个正整数n

输出(zip.out)

对于每组测试数据输出一行ans

样例输入

1

4

样例输出

4

样例解释:

0,2mod 4下不存在逆元;

1mod 4下逆元为1

3mod 4下逆元为3

数据范围:

20%的数据满足T<=101<n<10000n为质数;

50%的数据满足T<=101<=n<=10000

100%的数据满足T<=1001<=n<=109

两个性质

性质1:集合{[0,n-1]中存在逆元的数}==集合{[0,n-1]中存在逆元的数的逆元}

证明:因为对逆元再求逆元得到的是本身,它们就是一一对应的了

          这样问题就转化成了求[0,n-1]中与n互质的数的和

性质2[0,n-1]中与互质的数的和为

证明:因为gcd(n,i)=gcd(n,n-i)

      所以若 i 与 n 互质,那么 n-i 与 n 互质

      和f(i)=f(n-i)相似(大概吧)

      对称轴为x=(0+n)/2=n/2

      所以与n互质的数可以关于n/2对称的,也就是相加等于n

      每两个质数对答案贡献为n/2*2=n

      而现在有个质数

      所以答案为

     复杂度为求欧拉的复杂度,O( 根号n)

 代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 int T;
 6 long long n;
 7 long long phi(long long x)
 8 {
 9     long long ans=x;
10     for(long long i=2;i*i<=x;i++)
11     {
12         if(x%i==0)
13         {
14             ans/=i;
15             ans*=i-1;
16             while(x%i==0) x/=i;
17         }
18     }
19     if(x!=1) ans/=x,ans*=x-1;
20     return ans;
21 }
22 int main()
23 {
24     freopen("zip.in","r",stdin);
25     freopen("zip.out","w",stdout);
26     scanf("%d",&T);
27     while(T--)
28     {
29         scanf("%lld",&n);
30         printf("%lld\n",n*phi(n)/2);
31     }
32     return 0;
33 }
View Code

T2 老司机的彩虹桥

传送门

老司机的彩虹桥

rainbow.cpp/.c/.pas

题目描述:

自从老司机有了好多好多小司姬之后,老司机就造了一个好大好大的房子;

因为老司机非常的6,这个房子不在地上而在天上!

我们可以将这个房子抽象成n片云朵和n-1条彩虹,每一条彩虹上都住着一个小司姬,当然了,所有云朵是由这些彩虹连通的树哦;

现在老司机想去探望所有老司机的小司姬,但是麻烦的是,他并不能进到小司姬的房间里——也就是不能通过彩虹桥来移动;

所以每次他只能到一个云朵上,然后探望和那个云朵相连的彩虹桥上的小司姬;

老司机想知道,他最少要去多少个云朵上才能探望所有的小司姬;

老司机还想知道,有多少个云朵是在所有的最优方案中他都不会上去的;

老司机还想知道,他究竟有多少种最优方案来探望小司姬们呢?

如果你的回答让老司机满意的话,他也许会邀请你去看小司姬哦;

输入(rainbow.in)

第一行一个整数n,代表有n个云朵;

然后n-1行,每行有两个整数x,y

表示编号为xy的云朵之间有一个彩虹桥;

输出(rainbow.out)

输出有三行,每行有一个数字;

第一行:老司机最少到多少个云朵上去探望小司姬;

第二行:有多少个云朵老司机在最优方案中不会上去;

第三行:老司机有多少种最优方案来探望小司姬们;

注意到第三问的方案数可能很大,所以取模5462617输出,前两问不取模

样例输入

5

1 2

1 3

2 4

2 5

样例输出

2

2

2

数据范围:

30%的数据满足n<=1000

100%的数据满足n<=100000

评分标准:

本题分三个问题给分;

第一问每个测试点4,第二问每个测试点3,第三问每个测试点3

相应位置的数字正确会获得相应得分;

如果输出不足或超过三个数字则不给分;

树形DP

第一问

设 f [ x ] [ 0 ]表示 的子树满足条件并且不选 的最小代价;

设 f [ x ] [ 1 ]表示 的子树满足条件并且选 的最小代价;

最后答案就是 min ( f [ 1 ] [ 0 ],f [ 1 ] [ 1 ] )

第二问

设 p [ x ] [ 0 ]表示 点不选,除了 x 子树的所有部分的最小代价;

设 p [ x ] [ 1 ]表示 点选,除了 x 子树的所有部分的最小代价;

转移为:

当他自己不选,那么父节点必须选,此时整张图的代价为p [ fa[x] ] [ 1 ]+ f [ fa[x] ] [ 1 ] ,x的子树的贡献为 min ( f [ x ] [ 0 ] , f [ x ] [ 1 ] )

p [ x ] [ 0 ] = p [ fa[x] ] [ 1 ]+ f [ fa[x] ] [ 1 ] - min ( f [ x ] [ 0 ] , f [ x ] [ 1 ] )

若他自己选,那么父节点可选可不选

p [ x ] [ 1 ] = min ( p [ x ] [ 0 ] , p [ fa[x] ] [ 0 ] + f [ fa[x] ] [ 0 ] - f [ x ] [ 1 ] )

选了 x 点的最小答案就是 p [ x ] [ 1 ] + f [ x ] [ 1 ]

若这个答案大于第一问的结果,则 x 点永远不能选

第三问

设 t [ x ] [ 0 ]表示 x 的子树满足条件并且不选 x 的最小代价时的方案数;

设 t [ x ] [ 1 ]表示 x 的子树满足条件并且选 x 的最小代价时的方案数;

只是将第一问的累加变成了累乘

注意如果 f [ x ] [ 0 ] == f [ x ] [ 1 ] 也就是儿子两个都可以选的时候应该乘( t [ x ][ 1 ] + t [ x ][ 0 ] )

代码

 1 #include<cstdio>
 2 #include<iostream> 
 3 #define mod 5462617
 4 using namespace std;
 5 int ans,res,n,f[100010][2],k[100010][2],p[100010][2];
 6 int head[100010];
 7 //int to[100010],nxt[100010],cnt;
 8 //int t[100010][2];
 9 int to[200010],nxt[200010],cnt;
10 long long t[100010][2];
11 bool vis[100010];
12 void add(int a,int b)
13 {
14     cnt++;
15     nxt[cnt]=head[a];
16     head[a]=cnt;
17     to[cnt]=b;
18 }
19 int fa[100010];
20 void dfs(int x)
21 {
22     f[x][1]=1;
23     t[x][1]=t[x][0]=1;
24     for(int i=head[x];i;i=nxt[i])
25     {
26         if(to[i]==fa[x]) continue;
27         fa[to[i]]=x;
28         dfs(to[i]);
29         f[x][0]+=f[to[i]][1];
30         t[x][0]*=t[to[i]][1];
31         t[x][0]%=mod;
32         if(f[to[i]][1]<f[to[i]][0])
33         {
34             f[x][1]+=f[to[i]][1];
35             t[x][1]*=t[to[i]][1];
36             t[x][1]%=mod;
37         }
38         if(f[to[i]][1]==f[to[i]][0])
39         {
40             f[x][1]+=f[to[i]][1];
41             t[x][1]*=(t[to[i]][1]+t[to[i]][0])%mod;
42             t[x][1]%=mod;
43         }
44         if(f[to[i]][1]>f[to[i]][0])
45         {
46             f[x][1]+=f[to[i]][0];
47             t[x][1]*=t[to[i]][0];
48             t[x][1]%=mod;
49         }
50     }
51 }
52 void qiu(int x)
53 {
54     if(x>1)
55     {
56         //if(vis[fa[x]]==0) p[x][0]=ans-min(f[x][1],f[x][0]);
57         //p[x][1]=p[fa[x]][0]+f[fa[x]][0]-f[x][1];
58         p[x][0]=p[fa[x]][1]+f[fa[x]][1]-min(f[x][1],f[x][0]);
59         p[x][1]=min(p[x][0],p[fa[x]][0]+f[fa[x]][0]-f[x][1]);
60     }
61     if(p[x][1]+f[x][1]!=ans) vis[x]=1,res++;
62     for(int i=head[x];i;i=nxt[i])
63     {
64         if(to[i]==fa[x]) continue;
65         qiu(to[i]);
66     }
67 }
68 int main()
69 {
70     freopen("rainbow.in","r",stdin);
71     freopen("rainbow.out","w",stdout);
72     scanf("%d",&n);
73     for(int i=1,a,b;i<n;i++)
74     {
75         scanf("%d%d",&a,&b);
76         add(a,b);
77         add(b,a);
78     }
79     dfs(1);
80     ans=min(f[1][1],f[1][0]);
81     qiu(1);
82     if(f[1][1]>f[1][0])
83     {
84         printf("%d\n%d\n%lld\n",f[1][0],res,t[1][0]);
85     }
86     if(f[1][1]==f[1][0])
87     {
88         printf("%d\n",f[1][1]);
89         printf("%d\n",res);
90         printf("%lld\n",(t[1][0]+t[1][1])%mod); 
91     }
92     if(f[1][1]<f[1][0])
93     {
94         printf("%d\n%d\n%lld\n",f[1][1],res,t[1][1]);
95     }
96     return 0;
97 }
View Code

T3  小司姬的序列

传送门

小司姬的序列

girls.cpp/.c/.pas

题目描述:

自从老司机有了好多好多小司姬之后,老司机经常与她们一起玩游戏;

老司机总是喜欢吧小司姬们排成一列又一列的样子,然后向她们提出一些奇怪的问题,当然了,作为一个绅士,他是不会在询问开始之后再排列小司姬们的;

在序列中的每个小司姬都有一个可爱度ai,两个可爱度相同的小司姬视为相同的小司姬;

这一次,老司机提出的问题是这样的,对于两个小司姬序列x,y,它们相同的最长的小司姬序列有多长呢?(即查询两个序列的最长公共前缀LCP)

小司姬们当然会这个问题了,但是因为小司姬们实在是太可爱了,她们就又不会这个问题了,所以小司姬们向你求助,要你来解决这个问题;

如果你的回答让小司姬们满意的话,她们也许会邀请你一起来排队哦;

输入(girls.in)

第一行两个整数n,m,代表有n个序列,m次询问;

然后n行,每行为一个序列:

第一个整数len表示序列长度,然后len个整数为这个序列;

然后m行,每行两个整数x,y,表示老司机询问第x与第y个序列的LCP

输出(girls.out)

输出m行,每行为对老司机询问的答案;

样例输入

3 3

3 1 2 3

3 1 2 4

5 1 2 3 4 5

1 3

2 1

2 3

样例输出

3

2

2

数据范围:

50%的数据满足n<=1000m<=1000,序列总长度<=100000

其中30%的数据满足序列元素大小1<=ai<=26

100%的数据满足n<=100000m<=100000,序列总长度<=500000

序列元素大小0<=ai<=109

字符集较大=1e9

哈希+二分需要对出现的字符离散化

好难……

写一下Trie树吧

发现空间开不下

应用一个Trie的黑科技,长得像链式前向星

然后用map来存边

之后

LCA就是两字符串的LCP了

代码

 1 #include<cstdio>
 2 #include<map>
 3 /*
 4 map
 5 插入: p.insert(pair<int,string>(1, "student_one"));
 6 */
 7 using namespace std;
 8 int n,m,root,a[500010];
 9 int ed[100010];
10 int fa[500010][35],dep[500010],tot;
11 map<int,int> nxt[100010];
12 int insert(int len)
13 {
14     int x=root;
15     for(int i=1;i<=len;i++)
16     {
17         map<int,int>::iterator iter=nxt[x].find(a[i]);
18         if(iter==nxt[x].end())
19         {
20             nxt[x].insert(pair<int,int>(a[i],++tot));
21             iter=nxt[x].find(a[i]);
22             fa[tot][0]=x;
23         }
24         x=iter->second;
25     }
26     return x;
27 }
28 void dfs(int x,int deep)
29 {
30     dep[x]=deep;
31     for(map<int,int>::iterator i=nxt[x].begin();i!=nxt[x].end();i++)
32     {
33         dfs(i->second,deep+1);
34     }
35 }
36 int lca(int x,int y)
37 {
38     if(dep[x]<dep[y]) swap(x,y);
39     for(int i=30;i>=0;i--)
40     {
41         if(dep[x]==dep[y]) break;
42         if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
43     }
44     if(x==y) return x;
45     for(int i=30;i>=0;i--)
46     {
47         if(fa[x][0]==fa[y][0]) break;
48         if(fa[x][i]!=fa[y][i])
49         {
50             x=fa[x][i];
51             y=fa[y][i];
52         }
53     }
54     return fa[x][0];
55 }
56 int main()
57 {
58     freopen("girls.in","r",stdin);
59     freopen("girls.out","w",stdout);
60     scanf("%d%d",&n,&m);
61     for(int i=1,len;i<=n;i++)
62     {
63         scanf("%d",&len);
64         for(int j=1;j<=len;j++)
65         {
66             scanf("%d",&a[j]);
67         }
68         ed[i]=insert(len);
69     }
70     dfs(root,1);
71     for(int i=1;i<=30;i++)
72     {
73         for(int j=1;j<=tot;j++)
74         {
75             fa[j][i]=fa[fa[j][i-1]][i-1];
76         }
77     }
78     for(int i=1,a,b;i<=m;i++)
79     {
80         scanf("%d%d",&a,&b);
81         printf("%d\n",dep[lca(ed[a],ed[b])]-1);
82     }
83     return 0;
84 }
View Code

猜你喜欢

转载自www.cnblogs.com/QAQq/p/11317892.html