8.29题解

T1

考试打表两小时,终于找出了正解的规律,结果zz低错,直接挂掉70分。。。。。。

其实说实话打表找规律很好用,最开始我是发现对于一个质数$x$,$x^k$的约数和就是$x$的约数和+$\sum\limits_{i=2}^{k}{x^i}$,当然我考试的时候zz,这实际上就是$\sum\limits_{i=0}^{k}{x^i}$,这个可以直接等比数列求和,继续找规律,我们可以发现约数和是个积性函数,设$x$的约数和为$f(x)$,$x=p_1^{c_1}{\times}p_2^{c_2}{\times}{\cdots}{\times}p_n^{c_n}$,那么$f(x)=f(p_1^{c_1}){\times}f(p_2^{c_2}){\times}{\cdots}{\times}f(p_n^{c_n})$,然后分解质因数,直接累计答案就可以了

细数我的zz操作

1.在${\%}$意义下,想要除一个数,就直接除了,忘记需要乘逆元了

2.直接把两个超大质因数乘起来了,忘记了我有一个大于${\sqrt{n}}$的质因数了,没取模,直接炸了

3.这个很让人无语,由于我没有发现质数的约数和,和后面拼起来是完整的等比数列,于是我的等比数列求和最小的时候是$b-1$项,他的数据里恰好有$b=0$的情况,然后我的快速幂就死了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cmath>
 5 #define int long long
 6 #define maxn 1001000
 7 #define mod 9901
 8 using namespace std;
 9 int a,b,cnt,ts=-1,ans=1,sum;
10 int ss[maxn],pd[maxn],jl[maxn],flag[maxn];
11 vector <int> zys;
12 void shai(int x)
13 {
14     int s=sqrt(x);
15     for(int i=2;i<=s;++i)
16     {
17         if(!pd[i])  ss[++cnt]=i;
18         for(int j=1;j<=cnt&&i*ss[j]<=s;j++)
19         {
20             pd[i*ss[j]]=1;
21             if(i%ss[j]==0)  break;
22         }
23     }
24 }
25 int KSM(int a,int b)
26 {
27     int ans=1;  a=a%mod;
28     while(b>0)
29     {
30         if(b&1)  ans=(ans*a)%mod;
31         b=b>>1;  a=(a*a)%mod;
32     }
33     return ans%mod;
34 }
35 main()
36 {
37     scanf("%lld%lld",&a,&b);
38     if(b==0)  {printf("1\n");  return 0;}
39     shai(a);
40     for(int i=1;i<=cnt;++i)
41     {
42         if(ss[i]>a)  break;
43         if(!(a%ss[i]))  zys.push_back(ss[i]);
44         while(!(a%ss[i])&&a>1)  {jl[ss[i]]++;  a/=ss[i];}
45     }
46     if(a!=1)  {zys.push_back(a);  ts=a;}
47     for(int i=0;i<zys.size();++i)
48     {
49         if(zys[i]!=ts)
50         {
51             sum=zys[i]+1;
52             int da=KSM(zys[i],b*jl[zys[i]]-1);  da--;  da=da*KSM(zys[i]-1,mod-2);
53             int ls=(((zys[i]%mod*zys[i])%mod)*da)%mod;
54             sum=(sum+ls)%mod;  ans=(ans*sum)%mod;
55         }
56         else
57         {
58             sum=zys[i]+1;
59             int da=KSM(zys[i],b-1);  da--;  da=da*KSM(zys[i]-1,mod-2);
60             int ls=(((zys[i]%mod*zys[i])%mod)*da)%mod;
61             sum=(sum+ls)%mod;  ans=(ans*sum)%mod;
62         }
63     }
64     printf("%lld\n",ans);
65     return 0;
66 }

T2

这题,我考场上什么都没发现。。。

首先如果1的个数小于n那一定无解,然后哦按照东坡的吃法我们会发现其实让东坡尽量吃最后面的答案一定不会变差,所以我们可以考虑倒序枚举,假设把1看作1,把0看作-1,东坡和乡亲肯定都不能闲着,无论如何,乡亲都不会闲着,所以只需要保证东坡一直有的吃,我们根据那个-1,1的转化,倒序扫后缀和,显然当后缀和小于-1的时候东坡就没得吃了,可以手玩,此时我们只需要找一个最近的1和东坡眼前的0交换位置就可以了,这么贪心一定是正确的,但是由于空间开不到,所以只能得到70分的好成绩

考虑用后缀和,我们可以把他变成以m为单位,扫每个组中的后缀和,再加上他后面的组的后缀和,就是实际的后缀和,而这个组中后缀和最小的地方就是0最多,需要被挪的,挪一个0,花费是1,-1-最小的后缀和就是需要挪的步数,取最大就可以了

接下来考虑每个m重复多次的问题,重复多次,这个最小值要么在第一次,要么在最后一次,处理一下就可以了

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #define maxn 20001000
 5 #define maxx 10001000
 6 #define maxs 1001000
 7 using namespace std;
 8 int n,m,t,js,tot,sum,num,ans;
 9 int on[maxn],xl[maxn];
10 char a[maxs];
11 int main()
12 {
13     //freopen("meal4.in","r",stdin);
14     while(1)
15     {
16         scanf("%d%d",&n,&m);
17         if(!n&&!m)  break;
18         memset(xl,0,sizeof(xl));  memset(on,0,sizeof(on));
19         js=0;  tot=0;  sum=0;  num=0;  ans=0;
20         for(int i=1;i<=m;++i)
21         {
22             scanf("%s%d",a,&t);
23             int len=strlen(a);
24             for(int j=1;j<=t;++j)
25                 for(int k=0;k<len;++k)
26                 {
27                     if(a[k]==‘0‘)  xl[++js]=0;
28                     else  {xl[++js]=1;  tot++;  on[tot]=js;}
29                 }
30         }
31         if(tot<n)  {printf("-1\n");  continue;}
32         for(int i=2*n;i>=1;--i)
33         {
34             if(xl[i]==1)  {sum++;  num++;}
35             else
36             {
37                 sum--;
38                 if(sum==-2)
39                 {
40                     int pos=on[tot-num];
41                     sum=0;  xl[i]=1;  xl[pos]=0;  num++;
42                     ans=max(ans,i-pos);
43                 }
44             }
45         }
46         printf("%d\n",ans);
47     }
48     return 0;
49 }

贪心RE70

 1 //读入每一段的时候处理出来当前点在每一段中的后缀和,记录下这一段中的min和左端点的后缀和
 2 //而对于不断重复的每一个m,整个m中的最小值要么出现在第一段,要么出现在最后一段
 3 //第一段的话sum是几就是几在做贡献,最后一段的话做贡献的应该是sum+(t-1)sum<左>
 4 //最后的答案就是-1-最小的sum,因为最少需要这么多的0被移动
 5 #include<iostream>
 6 #include<cstring>
 7 #include<cstdio>
 8 #define int long long
 9 #define maxm 100100
10 #define maxs 1001000
11 #define inf 2000000000000000000
12 using namespace std;
13 int n,m,minnn,tot,sum,ans,hzh;
14 int minn[maxm],l[maxm],t[maxm];
15 char a[maxs];
16 main()
17 {
18     while(1)
19     {
20         scanf("%lld%lld",&n,&m);
21         if(!n&&!m)  break;
22         sum=0;
23         for(int i=1;i<=m;++i)
24         {
25             scanf("%s%lld",a,&t[i]);
26             int len=strlen(a);  tot=0;  minnn=inf;  int ls=0;
27             for(int k=len-1;k>=0;--k)
28             {
29                 if(a[k]==‘1‘)  {tot++;  ls++;}
30                 else  tot--;
31                 minnn=min(minnn,tot);
32             }
33             sum+=ls*t[i];  l[i]=tot;
34             minn[i]=min(minnn,l[i]*(t[i]-1)+minnn);
35         }
36         if(sum<n)  {printf("-1\n");  continue;}
37         ans=inf;  hzh=0;
38         for(int i=m;i>=1;--i)
39         {
40             ans=min(ans,minn[i]+hzh);
41             hzh+=l[i]*t[i];
42         }
43         printf("%lld\n",max(1ll*0,-1-ans));
44     }
45     return 0;
46 }

AC

T3

谁能想到暴力加上题目里给的程序就能水到50分,我反正没敢打那个。。。。

正解是DP,由于我们不可能枚举所有的状态,一种思路就是按位统计贡献,我们设$dp[i][j][k]$代表从大到小插入到了i,总积分为j,插入的这些数已经形成了k段的方案数,那么可以分为三种情况

1.插入这个数之后多了一段,那么后面再进的数一定都比这个数小,所以这个数的贡献是$2{\times}i$,对方案数的贡献是k+1,你原有的每个段左右都可以开一个新段,两个段之间的新段只能算一次,所以是k+1

2.插入这个数之后段数没变,那就是他有一边已经有一个数,这个数比他大,一边没有数,一会会再进一个比他小的,总贡献-i+i就是0,方案数的贡献就是$2{\times}k$

3.插入这个数之后段数少了一,也就是他左右两边都有数,那么对答案的贡献就是$-i{\times}2$,方案数是k-1

但很明显在我们上面的分类讨论中有一大类始终没有考虑到,就是如果这个数放在了左右端点上怎么办,显然在端点上对答案,对方案数的贡献都会改变,所以我们考虑在dp数组后面再加一维,分为0,1,2三种情况,表示现在已经考虑过的所有段里一共有几个端点,重新考虑上面三种情况

1.如果放在了端点上,对答案的贡献变为i

2.如果在端点上,对答案的贡献由0,变为-i

3.对答案的贡献由$-i{\times}2$变为-i

上述三种情况对方案数的贡献均为$2-$已有端点数,直接写转移方程转移就可以了

关于__float128卡精度那块,大佬们选择了用黑科技优化码量,DeepinC博客,我就直接复制粘贴了一遍,而且我跑的稍微有点慢,其实算是卡过去的,稍微不留神就会T

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 using namespace std;
  5 int n,m,xs;
  6 __float128 dpp[2][2100][55][3];
  7 void out1(int x,double ans)
  8 {
  9     if(x==0)  {printf("%0.0lf\n",ans);  return ;}
 10     if(x==1)  {printf("%0.1lf\n",ans);  return ;}
 11     if(x==2)  {printf("%0.2lf\n",ans);  return ;}
 12     if(x==3)  {printf("%0.3lf\n",ans);  return ;}
 13     if(x==4)  {printf("%0.4lf\n",ans);  return ;}
 14     if(x==5)  {printf("%0.5lf\n",ans);  return ;}
 15     if(x==6)  {printf("%0.6lf\n",ans);  return ;}
 16     if(x==7)  {printf("%0.7lf\n",ans);  return ;}
 17     if(x==8)  {printf("%0.8lf\n",ans);  return ;}
 18 }
 19 int floor(__float128 x)
 20 {
 21
 22     for(int i=9;i>=0;--i)
 23         if(x>=i)  return i;
 24 }
 25 void out2(int x,__float128 ans)
 26 {
 27     int sta[55];  sta[0]=0;
 28     for(int i=1;i<=x;++i)  {ans*=10;  sta[i]=floor(ans);  ans-=floor(ans);}
 29     ans*=10;
 30     if(floor(ans)>=5)  sta[x]++;
 31     for(int i=x;i;--i)
 32         if(sta[i]==10)  {sta[i]=0;  sta[i-1]++;}
 33     printf("%d.",sta[0]);
 34     for(int i=1;i<=x;++i)  printf("%d",sta[i]);
 35     puts("");
 36 }
 37 void work1()
 38 {
 39     double ans=0;
 40     double dp[2][7000][110][3];  dp[(n%2)^1][0][0][0]=1;
 41     for(int i=n;i>=1;--i)
 42     {
 43         int dq=i%2;
 44         memset(dp[dq],0,sizeof(dp[dq]));
 45         for(int j=0;j<=6666;++j)
 46         {
 47             for(int k=0;k<=n;++k)
 48             {
 49                 for(int l=0;l<=2;++l)
 50                 {
 51                     if(j-2*i>=0&&k-1>=0&&k-l>=0)
 52                         dp[dq][j][k][l]+=dp[dq^1][j-2*i][k-1][l]*(k-l);
 53                     if(j-i>=0&&k-1>=0&&l-1>=0)
 54                         dp[dq][j][k][l]+=dp[dq^1][j-i][k-1][l-1]*(3-l);
 55                     if(2*k-l>=0)  dp[dq][j][k][l]+=dp[dq^1][j][k][l]*(2*k-l);
 56                     if(l-1>=0)  dp[dq][j][k][l]+=dp[dq^1][j+i][k][l-1]*(3-l);
 57                     dp[dq][j][k][l]+=dp[dq^1][j+i*2][k+1][l]*k;
 58                 }
 59             }
 60         }
 61     }
 62     for(int j=m;j<=6666;++j)  ans+=dp[1][j][1][2];
 63     for(int i=1;i<=n;++i)  ans/=(double)i;
 64     out1(xs,ans);
 65 }
 66 void work2()
 67 {
 68     __float128 ans=0;
 69     dpp[(n%2)^1][0][0][0]=1;
 70     for(int i=n;i>=1;--i)
 71     {
 72         int dq=i%2;
 73         for(int j=0;j<=2000;++j)
 74             for(int k=0;k<=i;++k)
 75                 for(int l=0;l<=2;++l)  dpp[dq][j][k][l]=0;
 76         for(int j=0;j<=2000;++j)
 77         {
 78             for(int k=0;k<=i;++k)
 79             {
 80                 for(int l=0;l<=2;++l)
 81                 {
 82                     if(j-2*i>=0&&k-1>=0&&k-l>=0)
 83                         dpp[dq][j][k][l]+=dpp[dq^1][j-2*i][k-1][l]*(k-l);
 84                     if(j-i>=0&&k-1>=0&&l-1>=0)
 85                         dpp[dq][j][k][l]+=dpp[dq^1][j-i][k-1][l-1]*(3-l);
 86                     if(2*k-l>=0)  dpp[dq][j][k][l]+=dpp[dq^1][j][k][l]*(2*k-l);
 87                     if(l-1>=0)  dpp[dq][j][k][l]+=dpp[dq^1][j+i][k][l-1]*(3-l);
 88                     dpp[dq][j][k][l]+=dpp[dq^1][j+i*2][k+1][l]*k;
 89                 }
 90             }
 91         }
 92     }
 93     for(int j=m;j<=2000;++j)  ans+=dpp[1][j][1][2];
 94     for(int i=1;i<=n;++i)  ans/=(__float128)i;
 95     out2(xs,ans);
 96 }
 97 int main()
 98 {
 99     scanf("%d%d%d",&n,&m,&xs);
100     if(xs<=8)  work1();
101     else  work2();
102     return 0;
103 }

原文地址:https://www.cnblogs.com/hzjuruo/p/11477239.html

时间: 2024-10-08 15:03:42

8.29题解的相关文章

20160612~20160618 11

1.bzoj1597 http://www.lydsy.com/JudgeOnline/problem.php?id=1597 题意:n块土地,现在要求把土地分成几份,每份费用为该份中土地长最大值和宽最大值成绩,要求最小费用.n≤5000 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #

20160515~20160521

上星期生病结果没写题QAQ 健康还是很重要的! 20160516 1.bzoj3932 http://www.lydsy.com/JudgeOnline/problem.php?id=3932 题意:m个任务,任务(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束,优先级为Pi.n个询问,每次询问第Xi秒正在运行的任务中,优先级最小的Ki个任务的优先级之和是多少.若Ki大于第Xi秒正在运行的任务总数,输出第Xi秒任务优先级之和.m,n≤100000,强制在线. 代码: 1 #inclu

bzoj 1712: [Usaco2007 China]Summing Sums 加密

1712: [Usaco2007 China]Summing Sums 加密 Description 那N只可爱的奶牛刚刚学习了有关密码的许多算法,终于,她们创造出了属于奶牛的加密方法.由于她们并不是经验十足,她们的加密方法非常简单:第i只奶牛掌握着密码的第i个数字,起始的时候是Ci(0≤Ci<90000000).加密的时候,第i只奶牛会计算其他所有奶牛的数字和,并将这个数字和除以98765431取余.在所有奶牛计算完毕之后,每一只奶牛会用自己算得的数字代替原有的数字.也就是说, 这样,她们就完

20160403~20160409

20160405: 1.bzoj1306 http://www.lydsy.com/JudgeOnline/problem.php?id=1306 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 using namespace std; 6 7 int s2[10],ans[10],tot,n,s

洛谷 P1079 Vigen&#232;re 密码 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1079 题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为 南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用 M 表示:称加密后的信息为密文,用 C 表示:而密钥是一种

2017ZZUACM省赛选拔试题部分题解----谨以纪念我这卡线滚粗的美好经历

写在前面: 其实心里有些小小的不爽又有点小小的舒畅,为啥捏?不爽当然是因为没被选拔上啦,舒畅捏则是因为没被选拔上反而让自己警醒,学长也提点很多很多."沉下去,然后一战成名"学长如是对我说,我很开心.其实这完全算不算是题解,只是我个人的一些小想法而已.而且到现在还有一题不会...让自己长点记性吧. 题目 A :聪明的田鼠 Time Limit: 1 Sec Memory Limit: 128 MB Description 田鼠MIUMIU来到了一片农田,农田可以看成是一个M*N个方格的矩

Oyk的ACM刷题记录(始于2015年2月29日,可能含剧透)

Online Judge 题目序号/题目 简单大意/题解 犯2情况 2月29日 SPOJ GSS1  不带更新区间最大子段和. 线段树维护 区间从左/右开始的最大值.区间最大值.区间和. 1.输出忘了换行. 2.打错了一个字母. SPOJ GSS2 区间不重复最大子段和. 离线维护s[i..now],线段树维护 区间历史最大值.区间历史最大更新值.区间现在最大值.区间现在更新值. 询问输出区间历史最大值. 1.线段树询问忘记写pushdown了. SPOJ TEST 输出所有42前的数. 1.不

LeetCode: Longest Substring Without Repeating Characters 题解

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest subst

算法(第四版)C#题解&mdash;&mdash;1.4

写在前面 整个项目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp 这一节内容可能会用到的库文件有 Measurement 和 TestCase,同样在 Github 上可以找到. 善用 Ctrl + F 查找题目. 习题&题解 1.4.1 题目 证明从 N 个数中取三个整数的不同组合总数为 N(N - 1)(N - 2) / 6. 解答 即为证明组合计算公式: C(N, 3) = N! / [