期望: 60 + 30 + 20 = 110.实际: 40 + 0 + 10 = 50.
T1:给定一个正整数 M ,找出有多少不同的正整数对 (x, y) 使得存在正整数 p 和 q,满足下面这个方程:p*x2 + q*y = M.
S1:开局以为是数学题,套某个定理,想不到打了暴力,不知到>500的点为什么错了.后面跟dalao讨论,发现枚举的顺序有问题,导致TLE与WA.对于60pts,正确的打开方式应该为先枚举x( x<=sqrt ( m ) ),再枚举y( y<=m ),再枚举p.(p*x*x<m),一旦枚举到p,使x,y成立,就break.看上去o(n^3),其实为o(能过60pts).正解其实为暴力的优化,我们将p放在第二维枚举,第三维不枚举j,直接枚举m-x*x*p的因子,合法的y一定在其中,这样o(能过100pts)就解决了.
#include<iostream> #include<cstring> #include<cstdio> #include<vector> using namespace std; #define re register int T,m,ans,vis[200010]; vector<int> v[200010]; inline int fd(){ int s=1,t=0; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') s=-1; c=getchar(); } while(c>='0'&&c<='9'){ t=t*10+c-'0'; c=getchar(); } return s*t; } void work() { for(re int i=1;i<=200000;++i) for(re int j=1;j*i<=200000;++j) v[i*j].push_back(i); } int main() { freopen("pairs.in","r",stdin); freopen("pairs.out","w",stdout); T=fd(),work(); while(T--){ m=fd(); ans=0; for(re int x=1;x*x<=m;++x){ for(re int p=1;p*x*x<m;++p){ int cnt=v[m-x*x*p].size(); for(re int k=0;k<cnt;++k) if(!vis[v[m-x*x*p][k]]){ ++ans; vis[v[m-x*x*p][k]]=1; } } for(re int p=1;p*x*x<m;++p){ int cnt=v[m-x*x*p].size(); for(re int k=0;k<cnt;++k) vis[v[m-x*x*p][k]]=0; } } printf("%d ",ans); } return 0; }
T2:幼儿园老师正在给小朋友们排座位.一共有 N 个小朋友, M 个座位.为了尽量让小朋友分到自己喜欢的座位上去,决定让每个小朋友都选出两个自己最想坐的位置.小朋友们选好之后,老师却犯愁了.老师现在想知道,一共有多少种安排座位的方式能满足所有小朋友的意愿?由于答案可能很大,你需要将其对 10000019 取模后输出.
S2:显然30pts用于dfs,但是题目说明了小朋友选的两个座位可能是一样的,选择这两个座位的方案只算一种,在dfs要判重(30pts - > 0 pts).正解:考虑将座位看成点,小朋友喜欢的两个座位连一条双向边.我们要做的是将边定向.规定a-->b为选b,b-->a为选a.在一个n个点,m条边的联通块内,考虑以下几种情况:①:n<m,座位小于人数,显然无解.②:n-1==m.将每一个点做为根,都会使每一条边得到唯一方向,所以有n种方案.③:n==m,无自环.显然顺逆时针,两种方案.④:n==m,有自环,自环的两点选择唯一确定,全局方案唯一.最后利用乘法原理,将每个连通块的方案相乘即为ans.
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define re register const int mod=10000019; const int maxn=200010*10+10; int T,n,m,cnt,ans,vis[maxn],sum[maxn],head[maxn]; struct bian{ int next,to; }len[maxn<<1]; inline int fd(){ int s=1,t=0; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') s=-1; c=getchar(); } while(c>='0'&&c<='9'){ t=t*10+c-'0'; c=getchar(); } return s*t; } void add(int from,int to){ len[++cnt].to=to; len[cnt].next=head[from]; head[from]=cnt; } void dfs(int x,int &n,int &m,int &flag){ if(vis[x]) return; vis[x]=1; ++n,m+=sum[x]; for(re int k=head[x];k;k=len[k].next){ int to=len[k].to; if(to==x) flag=1; dfs(to,n,m,flag); } } int work(int x){ int n=0,m=0,flag=0; dfs(x,n,m,flag); m/=2; if(m>n) return 0; if(flag) return 1; if(n==m) return 2; return n; } int main() { freopen("seat.in","r",stdin); freopen("seat.out","w",stdout); T=fd(); while(T--){ n=fd(),m=fd(); memset(head,0,sizeof(head)); memset(vis,0,sizeof(vis)); memset(sum,0,sizeof(sum)); for(re int i=1;i<=n;++i){ int from=fd(),to=fd(); add(from,to),add(to,from); ++sum[from],++sum[to]; } ans=1; for(re int i=1;i<=m;++i) if(!vis[i]) ans=1ll*ans*work(i)%mod; printf("%d ",ans); } return 0; }
T3:给定一个整数 N ,请你计算 (7 +4√3 ) N 的整数部分模 1000000007 后的结果.
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define e exit(0) #define re register const int mod=1000000007; int T,n,ans; inline int fd(){ int s=1,t=0; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') s=-1; c=getchar(); } while(c>='0'&&c<='9'){ t=t*10+c-'0'; c=getchar(); } return s*t; } struct jz{ int a[5][5]; jz(){memset(a,0,sizeof(a));} jz operator*(const jz &p){ jz ans; for(re int k=1;k<=2;++k) for(re int i=1;i<=2;++i) for(re int j=1;j<=2;++j) ans.a[i][j]=(ans.a[i][j]%mod+1ll*a[i][k]*p.a[k][j]%mod)%mod; return ans; } }; jz work(){ jz g; g.a[1][1]=7,g.a[1][2]=4; g.a[2][1]=12,g.a[2][2]=7; return g; } jz qsm(jz k,int y){ jz ans; for(re int i=1;i<=2;++i) ans.a[i][i]=1; while(y){ if(y&1) ans=ans*k; k=k*k; y>>=1; } return ans; } int main() { freopen("math.in","r",stdin); freopen("math.out","w",stdout); T=fd(); while(T--){ n=fd(); if(n==0){ printf("1 "); continue; } else if(n==1){ printf("13 "); continue; } jz k=work(); k=qsm(k,n-1); ans=(1ll*7*k.a[1][1]%mod+1ll*4*k.a[2][1]%mod)%mod; ans=(1ll*2*ans%mod-1%mod)%mod; printf("%d ",ans); } return 0; }