【寒假集訓系列2.14】
擺脫了110魔咒...
30+100+0=130
誒呀第三題沒開long long一分都沒有啊...
T1Gcd
題目描述:
給定整數N,求1<=x,y<=N且Gcd(x,y)為素數的數對(x,y)有多少對.
輸入:
一個整數N
輸出:
如題
樣例輸入:
4
樣例輸出:
4
數據規模:
30%:N<=5000
100%: N<=10^7
這道題似乎以前聽過啊...然而不太會誒,枚舉gcd,然後找互質的數,突然一下子就忘記歐拉函數這個東西了...然後暴力於是30分
正解:歐拉篩一下,求出歐拉函數,把所有互質的個數求出來,然後枚舉gcd(),即質數,當然那些質數對(x,x)(x是質數)會被算兩次,要減掉
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdlib> 6 #include<ctime> 7 #include<cmath> 8 inline int read(){ 9 int ans=0,f=1;char chr=getchar(); 10 while(!isdigit(chr)){if(chr==‘-‘)f=-1;chr=getchar();} 11 while(isdigit(chr)) {ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} 12 return ans*f; 13 }const int N=1e7+5; 14 int n,prime[N],p[N],cnt,phi[N]; 15 long long sum[N],ans; 16 void pre(){ 17 phi[1]=1; 18 for(int i=2;i<=n;++i){ 19 if(prime[i]==0) 20 p[++cnt]=i,phi[i]=i-1; 21 for(int j=1;j<=cnt;++j){ 22 if(i*p[j]>n) break; 23 prime[i*p[j]]=1; 24 phi[i*p[j]]=(i%p[j]==0)?p[j]*phi[i]:phi[i]*(p[j]-1);//歐拉函數(積性函數) 25 } 26 } 27 } 28 int main(){ 29 // freopen("gcd.in","r",stdin); 30 // freopen("gcd.out","w",stdout); 31 n=read();pre(); 32 for(int i=1;i<=n;++i) sum[i]=sum[i-1]+phi[i];//前綴和 33 for(int i=1;i<=cnt;++i) ans+=sum[n/p[i]]*2; 34 printf("%lld\n",ans-cnt);//減掉質數對個數 35 }
T2寶藏
題目描述:
老胡在出模擬賽時想到了這樣一道題:給出一個網格圖,其中某些格子有寶物,每次從左上角出發,只能向下或右走,問至少走多少次才能將寶藏撿完。但這個問題對老胡來說太簡單了,現在假設每個格子中有好多寶物,而每一次經過一個格子至多只能撿走一個,至少走多少次才能把寶物全部撿完。
輸入:
第一行為正整數T,代表數據組數。
每組數據第一行為正整數N,M代表網格圖有N行M列,接下來N行每行M個非負整數,表示此格子中寶物數量,0代表沒有
輸出:
輸出一個整數,表示至少要走多少次。
樣例輸入:
1
3 3
0 1 5
5 0 0
1 0 0
樣例輸出:
10
數據規模:
30%: N,M<=5
50%: N,M<=100
100%: N,M<=1000,每個格子中寶物數不超過10^6
方法: Dilworth定理:DAG的最小鏈覆蓋=最大點獨立集
然而半天過不了樣例...i,j循環順序打反了...不會的同學搜一下Dilworth定理吧(O3不開也可以)
1 #pragma GCC optimize(3)//可以刪掉,打讀入優化的話完全不會TLE 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 #include<cstdlib> 7 #include<ctime> 8 #include<cmath> 9 using namespace std; 10 inline int read(){ 11 int ans=0,f=1;char chr=getchar(); 12 while(!isdigit(chr)){if(chr==‘-‘)f=-1;chr=getchar();} 13 while(isdigit(chr)) {ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} 14 return ans*f; 15 int x;scanf("%d",&x); 16 return x; 17 }const int M=1005; 18 int n,m,f[M][M]; 19 int main(){ 20 freopen("treasure.in","r",stdin); 21 freopen("treasure.out","w",stdout); 22 int T=read(); 23 while(T--){ 24 n=read(),m=read(); 25 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)f[i][j]=read(); 26 for(int j=1;j<=m;j++) 27 for(int i=n;i>0;i--) 28 f[i][j]=max(f[i][j]+f[i+1][j-1],max(f[i][j-1],f[i+1][j])); 29 printf("%d\n",f[1][n]); 30 } 31 return 0; 32 }
T3配對
題目描述:
給出一棵n個點的樹,將這n個點兩兩配對,求所有可行的方案中配對兩點間的距離的總和最大為多少。
輸入:
一個數n(n保證為偶數)。
接下來n-1行每行三個數x,y,z表示有一條長度為z的邊連接x和y。
輸出:
一個數表示答案。
樣例輸入:
6
1 2 1
1 3 1
1 4 1
3 5 1
4 6 1
樣例輸出:
7
樣例解釋:
配對方案:(1,2)(3,4)(5,6)
數據規模:
30%: N<=10
50%: N<=100
70%: N<=1000
100%: N<=10^5,z<=10^9
比賽的時候打了一個模擬退火+樹剖(+線段樹求距離)LCA(打算騙70分,噢真是可笑...),然後沒開long long成功爆0,否則20分(應該是參數沒調好)...
正解:分開對每一條邊考慮:若是要總值最大,那麽一條邊被計算的次數越多越好,然後記錄一下每個子樹的大小,取該點子樹大小和除去該子樹數其他部分大小的min值
文字看不懂的話就看代碼吧...出題人ciki表示這是一道智障題,然而沒有一個人拿分?
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<cstdlib> 6 #include<ctime> 7 #include<cmath> 8 #define int long long 9 using namespace std; 10 inline int read(){ 11 int ans=0,f=1;char chr=getchar(); 12 while(!isdigit(chr)){if(chr==‘-‘)f=-1;chr=getchar();} 13 while(isdigit(chr)) {ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();} 14 return ans*f; 15 }const int M=1e5+5; 16 int n,x,y,z,p[M]; 17 long long ans; 18 int head[M<<1],nxt[M<<1],ver[M<<1],val[M<<1],tot,sz[M]; 19 inline void add(int x,int y,int z){ver[++tot]=y;val[tot]=z;nxt[tot]=head[x];head[x]=tot;} 20 const double delta=0.998,t_min=1e-14; 21 void dfs(int x,int fa){sz[x]=1; 22 for(int i=head[x];i;i=nxt[i]){int y=ver[i]; 23 if(y==fa) continue; 24 dfs(y,x);sz[x]+=sz[y]; 25 ans+=val[i]*min(sz[y],n-sz[y]); 26 } 27 } 28 signed main(){ 29 freopen("match.in","r",stdin); 30 freopen("match.out","w",stdout); 31 n=read(); 32 for(int i=1;i<n;i++){x=read(),y=read(),z=read();add(x,y,z),add(y,x,z);} 33 dfs(1,0);cout<<ans; 34 return 0; 35 }
【寒假集訓系列2.14】