Loading

Noip模拟69 2021.10.5

考场拼命$yy$高精度结果没学好$for$循环痛失$50pts$,当场枯死

以后一定打对拍,要不考后会。。。

T1 石子游戏

首先要知道典型的$NIM$博弈,就是说如果所有堆石子个数的异或和为$0$则先手必输

那么这道题给出了取石子上限,那么每堆石子$\mod x+1$然后异或就可以知道谁必胜了

然后这道题就转化为如何求$\sum \limits_{i=1}^{n}\oplus a_i \mod(x+1)$。

分段考虑每一段$[k(x+1),(k+1)(x+1)]$,然后预处理一个$f$数组

 $UPD 2021.10.7$然而$A$掉这道题后发现并不是跟题解说的那样简单。

关于数组$f$:

题解里面预处理的$f$数组是基于位运算的,$f[i][j]$是由第$j+1$位加一个$1$转移过来的,

然后这一段区间使用了状压的思想枚举了子集算出的和累加的贡献,把后面的式子拆开就可以发现,累加的次数刚好为$[0,2^{j}-1]$,

这还表明了一个问题,就是只有偶数段才会做贡献。别着急问偶数段是啥,先听我说

刚才说累加的次数只有$2^j$次,而$2^{j+1}=2^{j} \times 2$是累加次数的二倍,再看累加的起点终点,

不难发现,如果把$2^j$长度称为一段,那么$2^{j+1}$就是两段,分开考虑这两段。

因为累加的起点在第二段开头也就是$i+2^j$而不是$i$,所以每次加上一个$2^{j+1}$长度的区间里面都只有第二段做出了累加的贡献

所以说只有偶数段才做贡献。

关于答案计算:

理解透彻$f$的转移方式之后便可以计算答案了。

对于枚举每一个$x+1$,我们枚举一个$j$,显然只会枚举到$log_2(x)$,然后我们再枚举一下可能的$k$

找到一段要计算的区间$[l,r]$,使用向下取整的方式找到距离$r$最近的$l+2^{j+1}$,这一段的贡献可以用预处理出的数组直接做后缀和求出

然后考虑区间$[l+2^{j+1},r]$,这段区间如果是在奇数区间,则不用计算单独的贡献,因为他没有,

如果有一些在偶数区间或者被偶数区间包含,就需要使用前缀和求出贡献,很好求,直接最右端减去最左端就行

算出的这个数如果是奇数,就会有贡献,给计数器上的$j$位异或一个$1$,因为要计算总和,现在枚举的是区间

需要找的是所有可能区间的答案的和是否为奇数,所以是异或,不是与,如果两个区间都是奇数那答案就会变成偶数。

这样就差不多了。

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define pw(x) (1<<(x))
 4 #define lg(x) (log2(x))
 5 using namespace std;
 6 namespace AE86{
 7     #define out(x) cout<<#x<<":"<<x<<endl
 8     #define fuck cout<<"fuck"<<endl
 9     inline int read(){
10         int x=0,f=1;char ch=getchar();
11         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
12         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
13     }inline void write(int x,char opt='\n'){
14         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
15         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
16         for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
17 }using namespace AE86;
18 const int NN=7e5+5;
19 int n,c[NN],f[NN][65];
20 namespace WSN{
21     inline short main(){
22         freopen("stone.in","r",stdin);
23         freopen("stone.out","w",stdout);
24         n=read();
25         for(int i=1;i<=n;i++) ++c[read()];
26         for(int i=1;i<=n;i++) c[i]+=c[i-1];
27         for(int i=n;~i;i--)
28             for(int j=0;j<=lg(n-i+1);j++)
29                 f[i][j]=f[min(i+pw(j+1),n)][j]+c[min(i+pw(j+1)-1,n)]-c[i+pw(j)-1];
30         for(int y=2;y<=n+1;y++){
31             int tmp=0; bool flag=0;
32             for(int j=0;j<=lg(y-1);j++){
33                 for(int k=0;k*y<=n;k++){
34                     int l=k*y,r=min((k+1)*y-1,n),floor=(r-l+1)>>(j+1); bool lim=(l+floor*pw(j+1)+pw(j)<=r);
35                     if((f[l][j]-f[l+floor*pw(j+1)][j]+lim*(c[r]-c[l+floor*pw(j+1)+pw(j)-1]))&1) tmp^=1<<j;
36                 }
37                 if(tmp){flag=1;break;}
38             }
39             printf(flag?"Alice ":"Bob ");
40         }
41         return 0;
42     }
43 }
44 signed main(){return WSN::main();}
View Code

 

 

 T2 大鱼吃小鱼

直接$multiset$水四十

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }inline void write(int x,char opt='\n'){
10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 const int NN=3e5+5;
15 int n,w[NN],q,stk[NN],top;
16 multiset<int> s;
17 #define sit multiset<int>::iterator
18 namespace WSN{
19     inline short main(){
20         // freopen("in.in","r",stdin); freopen("sb.out","w",stdout);
21         freopen("fish.in","r",stdin);
22         freopen("fish.out","w",stdout);
23         n=read();for(int i=1;i<=n;i++) w[i]=read(),s.insert(w[i]);
24         q=read();int tim=0;
25         while(q--){
26             int opt=read();++tim;
27             if(opt==1){
28                 int st=read(),k=read(),ans=0,flag=0;
29                 if(st>=k){write(0);continue;}
30                 top=0;
31                 while(s.size()){
32                     sit it=s.upper_bound(st-1);
33                     if(it!=s.begin()) --it;
34                     else {flag=1;break;}
35                     st+=*it; s.erase(it); stk[++top]=*it;
36                     ++ans;
37                     if(st>=k) break;
38                 }
39                 while(top) s.insert(stk[top--]);
40                 if(flag||st<k){puts("-1");continue;}
41                 write(ans);
42             }
43             if(opt==2){
44                 int v=read();s.insert(v);
45             }
46             if(opt==3){
47                 int v=read();s.erase(s.find(v));
48             }
49         }
50         return 0;
51     }
52 }
53 signed main(){return WSN::main();}
TLE40

 

T3 黑客

考场上没写出来的大水数论题,就是五分钟打了暴力就跑,没考虑正解(暴力分太高)

枚举分数算倍数个数就行

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }inline void write(int x,char opt='\n'){
10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 const int mod=1e9+7;
15 int A,B,C,D,ans;
16 inline int gcd(int a,int b){return b?gcd(b,a%b):a;}
17 inline int mo(int x){return x>=mod?x-mod:x;}
18 namespace WSN{
19     inline short main(){
20         freopen("hacker.in","r",stdin);
21         freopen("hacker.out","w",stdout);
22         A=read();B=read();C=read();D=read();
23         for(int i=1;i<=999;i++)
24             for(int j=1;j<=999-i;j++) if(gcd(i,j)==1){
25                 int l1=ceil(1.0*A/i),r1=B/i;
26                 int l2=ceil(1.0*C/j),r2=D/j;
27                 int a=min(r1,r2),b=max(l1,l2);
28                 if(a-b+1>0) ans=mo(ans+(i+j)*((a-b+1)%mod)%mod);
29         } write(ans);
30         return 0;
31     }
32 }
33 signed main(){return WSN::main();}
View Code

 

T4 黑客(续)

珍爱生命,远离高精

$m=0$加暴力可以获得$70pts$可是考场上没读明白那个限制条件就只打了$m=0$还打挂了

就爆零了,非常难受,以后还事能重载运算符就重载吧,要不一遍一遍的打太容易错

就是一个普通的数位$dp$套高精度,压位高精度到$17$位刚刚好,如果特判$m=0$会更快

$f[pos][sta]$表示$dp$到前$pos$位数字集合选择状态为$sta$时的方案/总和数。

  1 #include<bits/stdc++.h>
  2 #define int long long
  3 using namespace std;
  4 namespace AE86{
  5     inline int read(){
  6         int x=0,f=1;char ch=getchar();
  7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
  8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
  9     }inline void write(int x,char opt='\n'){
 10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
 11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
 12         for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
 13 }using namespace AE86;
 14 const int NN=1005;
 15 int n,m,k,ban[10];
 16 namespace TASK{
 17     int a[505],b[505],ad[505],c[5],bin[5][1005],d[1005],e[1005];
 18     inline void get(int *a,int x){for(;x;x/=10) a[++a[0]]=x%10;}
 19     inline void task1(){
 20         a[0]=a[1]=1;
 21         for(int T=1;T<=n;T++){
 22             memset(ad,0,sizeof(ad));
 23             for(int i=1;i<=a[0];i++){
 24                 int tmp=k*a[i];
 25                 a[i]=tmp%10; ad[i+1]=tmp/10;
 26                 if(ad[i]) a[i]+=ad[i];
 27                 if(a[i]>=10) ad[i+1]+=a[i]/10,a[i]%=10;
 28             } if(ad[a[0]+1]) a[0]++,a[a[0]]=ad[a[0]];
 29             if(T==n-1) memcpy(b,a,sizeof(a));
 30         }
 31         for(int i=a[0];i;--i) printf("%lld",a[i]);puts("");
 32         if(n==1){cout<<k<<endl;return;}
 33         int oo=(1+k)*k/2; get(c,oo);
 34         for(int i=1;i<=c[0];i++){
 35             memset(ad,0,sizeof(ad));
 36             for(int j=1;j<=b[0];j++){
 37                 int tmp=c[i]*b[j];
 38                 bin[i][j]=tmp%10; ad[j+1]=tmp/10;
 39                 if(ad[j]) bin[i][j]+=ad[j];
 40                 if(bin[i][j]>=10) ad[j+1]+=bin[i][j]/10,bin[i][j]%=10;
 41             }
 42             bin[i][0]=b[0];
 43             while(ad[b[0]+1]){
 44                 bin[i][++bin[i][0]]=ad[b[0]+1]%10;
 45                 ad[b[0]+1]/=10;
 46             }
 47             if(i!=1){
 48                 bin[i][0]+=(i-1);
 49                 for(int j=bin[i][0];j>=i-1;j--) bin[i][j]=bin[i][j-i+1];
 50                 for(int j=1;j<=i-1;j++) bin[i][j]=0;
 51             }
 52         }
 53         int maxn=0; memset(ad,0,sizeof(ad));
 54         for(int i=1;i<=c[0];i++) maxn=max(maxn,bin[i][0]);
 55         for(int i=1;i<=maxn;i++){
 56             int tmp=0;
 57             for(int j=1;j<=c[0];j++) tmp+=bin[j][i];
 58             ad[i+1]=tmp/10; d[i]=tmp%10;
 59             if(ad[i]) d[i]+=ad[i];
 60             if(d[i]>=10) ad[i+1]+=d[i]/10,d[i]%=10;
 61         } d[0]=maxn;
 62         while(ad[maxn+1]){
 63             d[++d[0]]=ad[maxn+1]%10;
 64             ad[maxn+1]/=10;
 65         }
 66         memcpy(e,d,sizeof(d));
 67         for(int i=1;i<n;i++){
 68             memset(ad,0,sizeof(ad));
 69             e[0]++;
 70             for(int j=e[0];j>1;j--) swap(e[j],e[j-1]);
 71             for(int j=1;j<=e[0];j++){
 72                 int tmp=d[j]+e[j];
 73                 ad[j+1]=tmp/10,d[j]=tmp%10;
 74                 if(ad[j]) d[j]+=ad[j];
 75                 if(d[j]>=10) ad[j+1]+=d[j]/10,d[j]%=10;
 76             } if(ad[(d[0]=e[0])+1]) d[0]++,d[d[0]]=ad[d[d[0]]];
 77         }
 78         for(int i=d[0];i;i--) printf("%lld",d[i]);puts("");
 79     }
 80 }using namespace TASK;
 81 namespace Solve{
 82     const int base=1e16;
 83     struct Big_Int{
 84         int p[65];
 85         Big_Int(){}
 86         Big_Int(int x){memset(p,0,sizeof(p));p[0]=(x>0);p[1]=x;}
 87         inline void print(){
 88             printf("%lld",p[p[0]]);
 89             for(int i=p[0]-1;i>0;--i) printf("%016lld",p[i]);
 90             puts("");
 91         }
 92         Big_Int operator*(const int&x){
 93             Big_Int ret; memset(ret.p,0,sizeof(ret.p)); int add=0; ret.p[0]=p[0];
 94             for(int i=1;i<=ret.p[0];++i){
 95                 ret.p[i]=p[i]*x+add;
 96                 add=ret.p[i]/base;
 97                 ret.p[i]-=add*base;
 98             }
 99             if(add) ret.p[++ret.p[0]]=add;
100             return ret;
101         }
102         Big_Int operator+(const Big_Int&a){
103             Big_Int ret; memset(ret.p,0,sizeof(ret.p)); int add=0; ret.p[0]=max(a.p[0],p[0]);
104             for(int i=1;i<=ret.p[0];++i){
105                 ret.p[i]=a.p[i]+p[i]+add;
106                 add=ret.p[i]/base;
107                 if(ret.p[i]>=base) ret.p[i]-=base;
108             }
109             if(add) ret.p[++ret.p[0]]=add;
110             return ret;
111         }
112     };
113     pair<Big_Int,Big_Int> f[505][1<<9];
114     pair<Big_Int,Big_Int> dfs(int pos,int sta){
115         if(f[pos][sta].first.p[1]>-1) return f[pos][sta];
116         if(pos>n) return f[pos][sta]=make_pair(Big_Int(1),Big_Int(0));
117         f[pos][sta].first.p[1]=0;
118         for(int i=1;i<=k;i++) if(!(sta&(ban[i]))){
119             pair<Big_Int,Big_Int> res=dfs(pos+1,sta|(1<<i-1));
120             f[pos][sta].first=f[pos][sta].first+res.first;
121             f[pos][sta].second=f[pos][sta].second+(res.first*i)+(res.second*10);
122         }
123         return f[pos][sta];
124     }
125 }using namespace Solve;
126 namespace WSN{
127     inline short main(){
128         freopen("hacker2.in","r",stdin);
129         freopen("hacker2.out","w",stdout);
130         n=read();m=read();k=read();
131         if(!m) return task1(),0;
132         for(int i=1,a,b;i<=m;++i) a=read(),b=read(),ban[a]|=1<<b-1;
133         for(int i=1;i<=n+1;i++)
134             for(int j=0;j<(1<<k);j++) f[i][j].first=Big_Int(-1);
135         pair<Big_Int,Big_Int> ans=dfs(1,0);
136         ans.first.print(); ans.second.print();
137         return 0;
138     }
139 }
140 signed main(){return WSN::main();}
View Code

 

posted @ 2021-10-06 07:55  雪域亡魂  阅读(139)  评论(0编辑  收藏  举报