csp-s模拟65Simple,Walk, Travel,棋盘题解

题面:https://www.cnblogs.com/Juve/articles/11639923.html

simple:

考试时只想到的暴力exgcd判断

考虑n,m互质的情况:

我们枚举y,对于方程$n*x+m*y leq q$,$xleqfrac{q-m*y}{n}$

其中y的范围是[0,n-1],因为如果y大于n-1,那么可以使x的系数加一,会有重复

然后如果n,m不互质,那么设$n=n'*gcd(n,m),m=m'*gcd(n,m)$,所以$n'*gcd(n,m)*x+m'*gcd(n,m)*y leq q$

其中把$gcd(n,m)*y$看成一个整体,那么枚举y的范围要保证$gcd(n,m)*yin[0,n-1]$

然后就A了

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define int long long
 6 using namespace std;
 7 const int MAXN=1e5+5;
 8 int t,n,m,q,ans;
 9 int gcd(int a,int b){
10     return b==0?a:gcd(b,a%b);
11 }
12 int max(int a,int b){return a>b?a:b;}
13 signed main(){
14     scanf("%lld",&t);
15     while(t--){
16         scanf("%lld%lld%lld",&n,&m,&q);
17         int g=gcd(n,m);
18         ans=0;
19         for(int i=0;i<(n/g);++i){
20             int x=q-i*m;
21             if(x<0) break;
22             ans+=x/n+1;
23         }
24         printf("%lld
",q-(ans-1));
25     }
26     return 0;
27 }
View Code

walk:

枚举gcd,然后把边权是gcd倍数的边建出来,形成一个森林,求出森林的直径即是答案为gcd时的边的长度

注意一点,有些长度可能不会出现在最长链中,因为他是构成最长链的一部分,所以如果这个长度的答案<长度大于他的答案的话,就要将长度大于他的答案给他,从大到小枚举ans[i]=max(ans[i],ans[i+1]).

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=4e5+5;
const int MAXM=1e6+5;
int n,maxx=0,res[MAXN],len=0;
vector< pair<int,int> >e[MAXM];
int to[MAXN<<1],nxt[MAXN<<1],pre[MAXN],cnt=0;
void add(int u,int v){
	++cnt,to[cnt]=v,nxt[cnt]=pre[u],pre[u]=cnt;
}
bool vis[MAXN];
int sta[MAXM],top=0;
int dfs(int x,int fa){
	vis[x]=1;
	int l=0,r=0;
	for(int i=pre[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa||vis[y]) continue;
		int p=dfs(y,x);
		if(p+1>l) r=l,l=p+1;
		else if(p+1>r) r=p+1;
	}
	len=max(len,l+r);
	return l;
}
int main(){
	scanf("%d",&n);
	for(int i=1,u,v,w;i<n;++i){
		scanf("%d%d%d",&u,&v,&w);
		maxx=max(maxx,w);
		e[w].push_back(make_pair(u,v));
	}
	for(int i=1;i<=maxx;++i){
		cnt=0;
		for(int j=i;j<=maxx;j+=i){
			int N=e[j].size();
			for(int k=0;k<N;++k){
				int u=e[j][k].first,v=e[j][k].second;
				add(u,v),add(v,u);
				sta[++top]=u,sta[++top]=v;
			}
		}
		for(int j=1;j<=top;++j){
			if(!vis[sta[j]]){
				len=0;
				dfs(sta[j],0);
				res[len]=max(res[len],i);
			}
		}
		for(int j=1;j<=top;++j){
			pre[sta[j]]=vis[sta[j]]=0;
		}
		top=0;
	}
	for(int i=n-1;i>=1;--i) res[i]=max(res[i],res[i+1]);
	for(int i=1;i<=n;++i) printf("%d
",res[i]);
	return 0;
}

棋盘:

容斥一发推式子:

$ans=sumlimits_{i=2}^{n}(-1)^i*A_{n}^{i}$

再加个高精度

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #define re register
  6 using namespace std;
  7 const int MAXN=205;
  8 int n,mp[MAXN][MAXN];
  9 struct bigint{
 10     int m[1005];
 11     inline friend bigint operator * (re bigint a,re int b){
 12         re int x=0;
 13         for(re int i=1;i<=a.m[0];i++){
 14             re int y=a.m[i]*b+x;
 15             a.m[i]=y%10;
 16             x=y/10;
 17         }
 18         while(x){
 19             a.m[++a.m[0]]=x%10;
 20             x/=10;
 21         }
 22         return a;
 23     }
 24     inline friend void operator += (re bigint &a,re bigint b){
 25         a.m[0]=max(a.m[0],b.m[0])+1;
 26         for(re int i=1;i<=a.m[0];++i) 
 27             a.m[i]+=b.m[i];
 28         for(re int i=1;i<=a.m[0];++i)
 29             if(a.m[i]>9) a.m[i]-=10,++a.m[i+1];
 30         while(a.m[0]!=1&&a.m[a.m[0]]==0) 
 31             --a.m[0];
 32     }
 33     inline friend bigint operator - (re bigint a,re bigint b){
 34         re bigint c;
 35         re int i=1;
 36         while((i<=a.m[0])||(i<=b.m[0])){
 37             if(a.m[i]<b.m[i]){
 38                 a.m[i]+=10;
 39                 a.m[i+1]--;
 40             }
 41             c.m[i]=a.m[i]-b.m[i];
 42             i++;
 43         }
 44         while(c.m[i]==0&&i>1)
 45             i--;
 46         c.m[0]=i;
 47         return c;
 48     }
 49     inline friend bigint operator * (re bigint a,re bigint b){
 50         re bigint c;
 51         memset(c.m,0,sizeof(c.m));
 52         c.m[0]=a.m[0]+b.m[0]+10;
 53         for(re int i=1;i<=a.m[0];++i){
 54             for(re int j=1;j<=b.m[0];++j){
 55                 c.m[i+j-1]+=a.m[i]*b.m[j];
 56             }
 57         }
 58         for(re int i=1;i<=c.m[0];++i){
 59             if(c.m[i]>9) c.m[i+1]+=c.m[i]/10,c.m[i]%=10;
 60         }
 61         while(c.m[0]!=1&&c.m[c.m[0]]==0) --c.m[0];
 62         return c;
 63     }
 64 }fac[MAXN],C[MAXN][MAXN],ans;
 65 inline void print(bigint a){
 66     for(re int i=a.m[0];i>=1;--i){
 67         printf("%d",a.m[i]);
 68     }
 69     puts("");
 70 }
 71 signed main(){
 72     //freopen("test.in","r",stdin);
 73     //freopen("ans.out","w",stdout);
 74     scanf("%d",&n);
 75     for(re int i=1;i<=n;++i){
 76         for(re int j=1,k;j<=n;++j){
 77             scanf("%d",&k);
 78             mp[i][j]=k;
 79         }
 80     }
 81     fac[0].m[0]=fac[0].m[1]=1;
 82     for(re int i=1;i<=n;++i) fac[i]=fac[i-1]*i;
 83     C[0][0].m[0]=C[0][0].m[1]=1;
 84     for(re int i=1;i<=n;++i){
 85         C[i][0].m[0]=C[i][0].m[1]=1;
 86         for(re int j=1;j<=i;++j){
 87             C[i][j]=C[i-1][j];
 88             C[i][j]+=C[i-1][j-1];
 89             //C[i][j]=C[i-1][j]+C[i-1][j-1];
 90         }
 91     }
 92     /*for(int i=1;i<=n;++i){
 93         for(int j=0;j<=i;++j){
 94             print(C[i][j]);
 95         }
 96         puts("");
 97     }*/
 98     ans=fac[n];
 99     for(re int i=1;i<=n;++i){
100         if(i&1) ans=ans-C[n][i]*fac[n-i];
101         else ans+=C[n][i]*fac[n-i];
102         //ans+=C[n][i];
103     }
104     print(ans);
105     return 0;
106 }
View Code
原文地址:https://www.cnblogs.com/Juve/p/11639943.html