[考試反思]1002csp-s模擬測試57:平庸


一天兩場,感覺要完。

不粘排行榜,太壯觀了。

#1:190

#2:180

#4:160

#35:150

#37:140

#39:120

#kx:20呃。。。

最后一個是考試結束后了。

又是CE蓋40分。其實離#2不遠。。。

調試語句沒刪干凈,開O2編譯出一條編譯錯誤,沒看,以為是那條關於scanf的warning。

然而並不是。

一定要仔細檢查編譯信息!!!交代碼前一定要編譯!!!

還有其實T1險些出鍋,看錯了題。

考試結束前7分鍾重新看了一遍發現不對勁,+100pts。

看題!!!

要檢查!!!

 

T1:天空龍

不會講。寫的超麻煩。

 1 #include<cstdio>
 2 main(){
 3     int t;scanf("%d",&t);
 4     while(t--){
 5         int a,b,c,x,y,z;scanf("%d%d%d%d%d%d",&a,&b,&c,&x,&y,&z);
 6         int det=(x>a)+(y>b)+(z>c);
 7         if(det==0){puts("YES");continue;}
 8         if(det==3){puts("NO");continue;}
 9         if(det==2){
10             if(a>=x)puts(a-x>>1>=y-b+z-c?"YES":"NO");
11             if(b>=y)puts(b-y>>1>=x-a+z-c?"YES":"NO");
12             if(c>=z)puts(c-z>>1>=x-a+y-b?"YES":"NO");
13         }
14         if(det==1){
15             if(x>a)puts(x-a<=(b-y>>1)+(c-z>>1)?"YES":"NO");
16             if(y>b)puts(y-b<=(a-x>>1)+(c-z>>1)?"YES":"NO");
17             if(z>c)puts(z-c<=(a-x>>1)+(b-y>>1)?"YES":"NO");
18         }
19     }
20 }
View Code

 

T2:巨神兵

數據范圍顯然狀壓n,但是狀壓表示什么?

因為要造DAG,所以一定有拓撲序,就存哪些點已經被拓撲了就行。

但是有的DAG的拓撲序不唯一。要容斥掉。(容斥系數我會證了感謝吧人擦)

枚舉補集的子集,枚舉子集的高效方法一直不會,上網頹了一個。

for(int st=S;st;(--st)&=S);這樣st就會遍歷S的所有子集。

這題也嚴重卡常,不能通過直接枚舉n來判斷二進制下是否存在這個點,而是要lowbit來直接取出一位。

 1 #include<cstdio>
 2 #define mod 1000000007
 3 int fir[18],l[299],to[299],cnt,n,m,cr[18],sz[1666666],pre[18],re[1666666];
 4 long long pw[111],dp[1666666];
 5 void link(int a,int b){l[++cnt]=fir[a];fir[a]=cnt;to[cnt]=b;}
 6 main(){//freopen("obelisk8.in","r",stdin);
 7     dp[0]=pw[0]=1;
 8     scanf("%d%d",&n,&m);
 9     for(int i=1,x,y;i<=m;++i)scanf("%d%d",&x,&y),link(x,y);
10     for(int st=1;st<1<<n;++st)sz[st]=sz[st^st&-st]+1;
11     for(int i=1;i<=n;++i)re[1<<i-1]=i;
12     for(int i=1;i<=100;++i)pw[i]=(pw[i-1]<<1)%mod;
13     for(int i=1;i<=n;++i)for(int j=fir[i];j;j=l[j])pre[i]|=1<<to[j]-1;
14     for(int st=0;st<1<<n;++st)
15         for(int U=(~st)&(1<<n)-1,S=U;S;(--S)&=U){
16             int cnt=0;
17             for(int i=st;i;i^=i&-i)cnt+=sz[S&pre[re[i&-i]]];
18             (dp[st|S]+=dp[st]*pw[cnt]*(sz[S]&1?1:-1)%mod+mod)%=mod;
19         }
20     printf("%lld\n",dp[(1<<n)-1]);
21 }
View Code

思路積累:

  • DAG-dp:拓撲序的狀態壓縮
  • 神奇容斥

 

T3:太陽神

40%的暴力寫在黑板上了,其實不M的話是60,附個代碼。

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 int n,pr[30000005],md[100000005],prcnt;
 5 bool np[100000005];long long Ans=1;short ans[100000001],mdcnt[100000001];
 6 int main(){
 7     scanf("%d",&n);
 8     for(int i=2;i<=n;++i){
 9         if(!np[i])ans[i]=3,pr[++prcnt]=i,mdcnt[i]=1,md[i]=i;
10         for(int j=1;j<=prcnt&&i*pr[j]<=n;++j){
11             int T=i*pr[j];
12             md[T]=pr[j];np[T]=1;
13             mdcnt[T]=md[i]==pr[j]?mdcnt[i]+1:1;
14             ans[T]=ans[i]/(mdcnt[T]*2-1)*(mdcnt[T]*2+1);
15             if(i%pr[j]==0)break;
16         }
17     }
18     for(int i=2;i<=n;++i)Ans+=ans[i];
19     printf("%lld\n",(1ll*n*n-Ans)%1000000007);
20 }
View Code

另一種40~60的打法是cbx的,在下面說。

第一雞房的不少都是用反演A的,我太菜我不會。

我跟cbx走的。

瘋狂的數論分塊就好了。

問題就是怎么求下發題解里的f函數,求出f值后就可以在外層數論分塊n/d做了。

觀察f數組,把它差分一下得到g,g[k]是什么含義?

是[gcd(a,b)==1]×a×b==k的a,b對數。

考慮含義,既然乘積一定,那么把k分解質因數之后把因子分配給ab就好了。

如果一種因子有多個,那么一定只分給ab里的一個,否則gcd不為1。

那么其實g[k]的值就是2k的質因子(不是個數)。可以線篩

然后做一遍前綴和就可以得到f了。

怎么求S函數呢?一個比較直接的數論分塊。

然后對於大的f值就可以遞歸求了。

沒有想象的那么難,雖然不是很會證。

 1 #include<cstdio>
 2 #define int long long
 3 #define mod 1000000007
 4 int pr[8000005],md[10000005],prcnt,f[10000005];
 5 bool np[10000005];int n,Ans;
 6 int S(int k){
 7     int ans=0;
 8     for(int i=1,lst;i<=k;i=lst+1)lst=k/(k/i),(ans+=(lst-i+1)%mod*(k/i))%=mod;
 9     return ans;
10 }
11 int F(int k){
12     if(k<=10000000)return f[k];int ans=0;
13     for(int j=2;j*j<=k;++j)(ans+=F(k/j/j))%=mod;
14     return (S(k)-ans+mod)%mod;
15 }
16 main(){
17     scanf("%lld",&n);f[1]=1;
18     for(int i=2;i<=10000000;++i){
19         if(!np[i])f[i]=2,pr[++prcnt]=i,md[i]=i;
20         for(int j=1;j<=prcnt&&i*pr[j]<=10000000;++j){
21             int T=i*pr[j];
22             md[T]=pr[j];np[T]=1;
23             f[T]=(f[i]<<(md[i]!=pr[j]))%mod;
24             if(i%pr[j]==0)break;
25         }
26     }
27     for(int i=2;i<=10000000;++i)(f[i]+=f[i-1])%=mod;
28     for(int i=1,lst;i<=n;i=lst+1)lst=n/(n/i),(Ans+=(lst-i+1)%mod*F(n/i)+mod)%=mod;
29     printf("%lld\n",(n%mod*(n%mod)%mod-Ans+mod)%mod);
30 }
View Code

思路積累:

  • 數論分塊:竟然是聯賽知識點啊
  • 線篩:肯定是聯賽知識點

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM