天天看點

17.10.25

    • 上午
      • 模拟考試
      • Prob.1(AC)用用<cmath>裡的sin和cos就好

注意一個細節:因為double的精度問題,輸出0是可能會輸出-0。

要特判一下。

      • Prob.2(WA)矩陣幂優化線性遞推,但我制杖地把遞推寫錯了一個地方。

考試時有多餘時間一定要寫暴力對拍啊,(可惡的萬能樣例竟然還過了)

      • Prob.3(70)正解是線段樹優化dp,(用線段樹維護一個區間的最大值,log2n級别轉移)

我寫了一個差分限制(用的裸的spfa),過了70分。但之後把spfa用雙端隊列deque或者優先隊列優化以後,就快得飛起來,比正解(線段樹+dp,這個差分限制也算正解了吧)還快。

    • 下午
      • 改了改題,學了學上午考試第三題正解
      • BOZJ 1072 半天沒搞出來,效率太低了。
      • 、、、
    • 晚上
      • BOZJ 1072 [SCOI2007]排列perm

dp[s][j]:表示s這個集合中的數構成的對d取模後等于j的數有多少個。

然後有一個小結論:

若 j=A%d,令 x=(A*10+B)%d,則 (j*10+B)%d==x

這個也很顯然:

令 A=k*d+j,

則 x=((k*d+j)*10+B)%d

    =(k*d*10+j*10+B)%d

    =(j*10+B)%d

是以轉移如下:

dp[s|(1<<k)][(j*10+s[k]-'0')%d]+=dp[s][j];

最後處理一下出現多次的數字。因為不考慮相同數字的順序,是以除以其出現次數的階乘。

代碼:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char s[15];
int dp[1<<10][1005],c[15],fac[15];
int T,d,n;
int idx(char ch){
	return ch-'0';
}
int main(){
	scanf("%d",&T); fac[0]=1;
	for(int i=1;i<=10;i++) fac[i]=fac[i-1]*i;
	while(T--){
		scanf("%s",s);
		scanf("%d",&d);
		memset(dp,0,sizeof(dp));
		dp[0][0]=1; n=strlen(s);
		for(int i=0;i<(1<<n);i++)
			for(int j=0;j<d;j++){
				if(!dp[i][j]) continue;
				for(int k=0;k<n;k++){
					if(i&(1<<k)) continue;
					dp[i|(1<<k)][(j*10+idx(s[k]))%d]+=dp[i][j];
				}
			}
		memset(c,0,sizeof(c));
		for(int i=0;i<n;i++) c[idx(s[i])]++;
		for(int i=0;i<10;i++) dp[(1<<n)-1][0]/=fac[c[i]];
		printf("%d
",dp[(1<<n)-1][0]);
	}
	return 0;
}
      
    • BZOJ 1073 還沒打完……
  • 今天效率是真的低啊!再這樣下次考試就要爆零了。