NOIp2018集训test-10-17 (bike day3)

发现自己gradully get moodier and moodier了

负面情绪爆发地越来越频繁,根本out of control,莫名其妙地就像着了魔一样

为什么用英语大概是因为今天早上早自习因为英语考了全班倒数被hj抽上黑板去听写了,就很开心

B 君的第一题 (guangzhou)

虽然我完全不知道Bike在说些什么,但是ycl告诉我,因为任何高斯整数都可以这样表达出来,相当于是把高斯整数表示成一个p进制数,每一位是0或者1。然后手写复数类进制转换就好了。

看模p等不等于0可以不用重载模运算,直接看(a+b)%2是否等于0,llj说,因为(-i-1)^2=2i,所以(-i-1)^k一定可以表达成(2i)^k1或者(2i)^k1*(-i-1),这样大概就可以证这个了。

 1 //Achen
 2 #include<bits/stdc++.h>
 3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 5 #define Formylove return 0
 6 const int N=10007;
 7 typedef long long LL;
 8 typedef double db;
 9 using namespace std;
10 int ans[N];
11 
12 template<typename T> void read(T &x) {
13     char ch=getchar(); x=0; T f=1;
14     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
15     if(ch=='-') f=-1,ch=getchar();
16     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
17 }
18 
19 struct fs {
20     LL a,b;
21     fs(){}    
22     fs(LL a,LL b):a(a),b(b){}
23 }bs,tp;
24 
25 fs operator *(const fs&A,const fs&B) { return fs(A.a*B.a-A.b*B.b,A.a*B.b+A.b*B.a); }
26 fs operator /(const fs&A,const LL&B) { return fs(A.a/B,A.b/B); }
27 fs operator /(const fs&A,const fs&B) { return A*fs(B.a,-B.b)/(B.a*B.a+B.b*B.b);  }
28 
29 #define ANS
30 int main() {
31 #ifdef ANS
32     freopen("guangzhou.in","r",stdin);
33     freopen("guangzhou.out","w",stdout);
34 #endif
35     LL a,b;
36     read(a); read(b);
37     bs=fs(a,b);
38     tp=fs(-1,-1);
39     for(int i=0;(bs.a!=0||bs.b!=0);i++) {
40         if((bs.a+bs.b)&1) {
41             ans[++ans[0]]=i;
42             bs.a=bs.a-1;
43         }
44         bs=bs/tp;
45     }
46     printf("%d\n",ans[0]);
47     For(i,1,ans[0]) printf("%d\n",ans[i]);
48     Formylove;
49 }
View Code

另外llj告诉了我如何证明任意整数都可以用若干不等的斐波那契数表示,

归纳证明,f[0]~f[i]可以表达1~f[i+1]的所有数,

i=1时成立,

于是f[0]~f[i+1]就可以表达1~f[i+2]所有数

找整数的表达的时候贪心地每次找到小于这个数的最大斐波那契数减去即可,

∵f[i]<=x<f[i+1],∴x-f[i]<f[i-1] 又∵f[0]~f[i-1]可以表达1~f[i]所有数,得证

 

B 君的第二题 (hangzhou)

条件有a<2333^2

a<2333时就是问长度大于等于2的单调不升子序列的个数,树状数组优化dp即可

n<2333时就是加上限制这个序列中相邻两项的组合数mod2333不等于0,也就是x!/(y!(x-y)!)mod 2333不等于0,∴x/2333=y/2333+(x-y)/2333

n^2dp就可以做75pt了。

x/p=y/p+(x-y)/p 转化成 y mod p + (x-y) mod p < p  ∴y mod p <= x mod p

∵y<=x ∴y/p<=x/p

因为当时我太蠢没有想到所以绕了圈子,其实一个lucas定理就直接得出 y/p<=x/p&&y mod p <= x mod p了

然后二维树状数组维护即可。

 1 //Achen
 2 #include<bits/stdc++.h>
 3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 5 #define Formylove return 0
 6 const int N=233333+13,P=2333,mod=1000000007;
 7 typedef long long LL;
 8 typedef double db;
 9 using namespace std;
10 int n,a[N];
11 LL f[N];
12 
13 template<typename T> void read(T &x) {
14     char ch=getchar(); x=0; T f=1;
15     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
16     if(ch=='-') f=-1,ch=getchar();
17     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
18 }
19 
20 LL mo(LL x,int p) { return x<0?x+p:(x>=p?x-p:x); }
21 
22 LL sum[2340][2340];
23 void add(int x,int y,LL v) {
24     for(int i=x;i<=P;i+=(i&(-i))) 
25         for(int j=y;j<=P;j+=(j&(-j)))
26             sum[i][j]=mo(sum[i][j]+v,mod);
27 }
28 
29 LL qry(int x,int y) {
30     LL rs=0;
31     for(int i=x;i;i-=(i&(-i))) 
32         for(int j=y;j;j-=(j&(-j)))
33             rs=mo(rs+sum[i][j],mod);
34     return rs;
35 }
36 
37 #define ANS
38 int main() {
39 #ifdef ANS
40     freopen("hangzhou.in","r",stdin);
41     freopen("hangzhou.out","w",stdout);
42 #endif
43     read(n); int mx=0;
44     For(i,1,n) {
45         read(a[i]);
46         mx=max(mx,a[i]);
47     }
48     LL ans=0;
49     For(i,1,n) {
50         int x=P-a[i]/P,y=P-a[i]%P;
51         f[i]=qry(x,y);
52         ans=mo(ans+f[i],mod);
53         f[i]=mo(f[i]+1,mod);
54         add(x,y,f[i]);
55     }
56     printf("%lld\n",ans);
57     Formylove;
58 }
View Code

 

B 君的第三题 (nanjing)

这好像不是我第一次两个dp能解决的问题前一半用dp后一半写搜索然后TLE了。虽然这次好像后一半我确实也不会写。当然前一半也写得稀丑。

然而bike老爷就非常优秀了——当然像这三道题这种简单的题对于毕老爷都是套路签到水题十分钟就能切完,但对于我这种见识浅薄又愚钝的人来说十分否奥妙和优秀了——先预处理出c[s]表示原图中两端都在s集合里面的边数,用子集和变换就可以处理。

f[k][s]表示s集合形成k个联通块的方案数,先dp出f[1]。

s联通的方案就是总方案数减去不连通的方案,枚举定点所在的联通块来转移就可以了。(我都可以想象到llj说”这不是弱智套路题吗?“时看智障的表情了,真是菜得抠脚)

这里每个集合选择的定点是lowbit。

然后dp出f[2~k],方法类似,对每个集合固定最后一个联通块是lowbit所在的联通块来转移。

 1 //Achen
 2 #include<bits/stdc++.h>
 3 #define For(i,a,b) for(int i=(a);i<=(b);i++)
 4 #define Rep(i,a,b) for(int i=(a);i>=(b);i--)
 5 #define Formylove return 0
 6 const int N=1007,p=1000000007;
 7 typedef long long LL;
 8 typedef double db;
 9 using namespace std;
10 int n,m,k,pr[N],f[20][16391],c[16391],ans;
11 
12 template<typename T> void read(T &x) {
13     char ch=getchar(); x=0; T f=1;
14     while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
15     if(ch=='-') f=-1,ch=getchar();
16     for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
17 }
18 
19 LL mo(LL x) { return x<0?x+p:(x>=p?x-p:x); }
20 
21 #define ANS
22 int main() {
23 #ifdef ANS
24     freopen("nanjing.in","r",stdin);
25     freopen("nanjing.out","w",stdout);
26 #endif
27     pr[0]=1;
28     For(i,1,1001) pr[i]=(LL)pr[i-1]*2%p;
29     read(n); read(m); read(k); 
30     For(i,1,m) {
31         int x,y;
32         read(x); read(y);
33         c[pr[x-1]+pr[y-1]]++;
34     }
35     int up=pr[n]-1;
36     For(i,1,n) For(s,1,up) if(s&pr[i-1]) 
37         c[s]=mo((LL)c[s]+c[s^pr[i-1]]);
38     For(s,1,up) {
39         int S=((s-1)&s);
40         LL t=0;
41         for(int ss=S;ss;ss=((ss-1)&S))
42             t=mo(t+(LL)f[1][s^ss]*pr[c[ss]]%p);
43         f[1][s]=mo(pr[c[s]]-t);
44     }
45     For(t,2,k) For(s,1,up) {
46         int S=((s-1)&s);
47         for(int ss=S;ss;ss=((ss-1)&S)) {
48             f[t][s]=mo((LL)f[t][s]+(LL)f[t-1][ss]*f[1][s^ss]%p);
49         }
50     }
51     printf("%d\n",f[k][up]);
52     Formylove;
53 }
View Code

 

posted @ 2018-10-17 21:37  啊宸  阅读(214)  评论(0编辑  收藏  举报