B Interesting pathshtml
考察範圍:組合數學java
此題是機器人走方格的變種,n*m的網格,從(1,1)走到(n,m),首先能夠明確,水平要走m-1格,豎直要走n-1格,則走到目的地的任意一條路徑必須走n+m-2格,呢麼只要肯定豎直要走的,剩下的就是水平要走的,則答案爲node
。ios
在Interseting paths要求左下角和右上角兩個小矩陣不能走,則須要把整個網格依據兩個小矩陣的水平和豎直邊界分爲兩部分,依次運用組合數。例如c++
灰色區域以外爲可走區域,分爲兩部分棕色,和黃色,則結果爲ide
如果這種狀況,則可分爲兩個ui
則結果爲spa
因此須要兩次分割,分別處理c到a和b到d。3d
由於n,m的範圍比較大,能夠提早預處理1到2*10^5的全部組合數和逆元。rest
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <vector> #include <queue> #include <stack> #include <cstdlib> #include <iomanip> #include <cmath> #include <cassert> #include <ctime> #include <map> #include <set> using namespace std; #pragma comment(linker, "/stck:1024000000,1024000000") #pragma GCC diagnostic error "-std=c++11" #define lowbit(x) (x&(-x)) #define max(x,y) (x>=y?x:y) #define min(x,y) (x<=y?x:y) #define MAX 100000000000000000 #define MOD 998244353 #define pi acos(-1.0) #define ei exp(1) #define PI 3.1415926535897932384626433832 #define ios() ios::sync_with_stdio(true) #define INF 0x3f3f3f3f #define mem(a) ((a,0,sizeof(a))) typedef long long ll; const ll mod=1000000007; ll fic[200006],jie[200006]; ll t,n,m,a,b,c,d; ll quick_pow(ll x,ll y){//求逆元 ll ans=1; while(y){ if(y&1) ans=ans*x%mod; y>>=1; x=x*x%mod; } return ans; } void get_fic(){ fic[0]=1; jie[0]=quick_pow(fic[0],mod-2); for(int i=1;i<=200004;i++){ fic[i]=fic[i-1]*i%mod; jie[i]=quick_pow(fic[i],mod-2); } } int main(){ get_fic();//預處理全部值 scanf("%lld",&t); while(t--){ scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&a,&b,&c,&d); ll ans=0; for(int i=c+1;i<a;i++){//豎直處理 ll l=fic[b+i-2]*jie[b-1]%mod*jie[i-1]%mod; ll r=fic[m-b+n-i-1]*jie[m-b-1]%mod*jie[n-i]%mod; ans=(ans+(l*r)%mod)%mod; } for(int i=b+1;i<d;i++){//水平處理 ll l=fic[c+i-2]*jie[c-1]%mod*jie[i-1]%mod; ll r=fic[m-i+n-c-1]*jie[m-i]%mod*jie[n-c-1]%mod; ans=(ans+(l*r)%mod)%mod; } printf("%lld\n",ans); } return 0; }
C 三角平方數
設三角數爲m,平方數爲n則根據題意有n^2=(1/2)(m+1)m,化簡可得 8n^2=4m^2+4m+1-1==>
(2m+1)^2-2(2n)^2=1
令x=2m+1,y=2n則有 x^2-2y^2=1可知爲佩爾方程標準形式,特解爲x=3,y=2,因此能夠轉化爲矩陣乘法求任意一個解(佩爾方程)。
import java.util.*; import java.io.*; import java.math.*; public class Main{ static Scanner cin=new Scanner(System.in); static PrintWriter cout=new PrintWriter(System.out,true); public static BigInteger[][] multiply_matrix(BigInteger[][] a,BigInteger[][] b){ BigInteger[][] c=new BigInteger[2][2]; c[0][0]=BigInteger.valueOf(0); c[0][1]=BigInteger.valueOf(0); c[1][0]=BigInteger.valueOf(0); c[1][1]=BigInteger.valueOf(0); for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int k=0;k<2;k++) c[i][j]=c[i][j].add(a[i][k].multiply(b[k][j])); return c; } public static BigInteger quick_pow(int y){ BigInteger[][] ans=new BigInteger[2][2]; BigInteger[][] pos=new BigInteger[2][2]; ans[0][0]=BigInteger.valueOf(1); ans[0][1]=BigInteger.valueOf(0); ans[1][0]=BigInteger.valueOf(0); ans[1][1]=BigInteger.valueOf(1); pos[0][0]=BigInteger.valueOf(3); pos[0][1]=BigInteger.valueOf(4); pos[1][0]=BigInteger.valueOf(2); pos[1][1]=BigInteger.valueOf(3); while(y!=0){ if(y%2==1) ans=multiply_matrix(ans,pos); y=y/2; pos=multiply_matrix(pos,pos); } return ans[1][0]; } public static void main(String[] args){ int n=cin.nextInt(); BigInteger result=quick_pow(n); result=result.divide(BigInteger.valueOf(2)); cout.println(result.multiply(result)); } }
F Star
考察範圍:最小生成樹
任意兩個主星球之間均可以選擇是否進行空間奇點壓縮,選擇不壓縮就是三維排序,壓縮就分別去掉x,y,z進行二維排序,最後跑最小生成樹便可。
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <vector> #include <queue> #include <stack> #include <cstdlib> #include <iomanip> #include <cmath> #include <cassert> #include <ctime> #include <map> #include <set> using namespace std; #pragma comment(linker, "/stck:1024000000,1024000000") #pragma GCC diagnostic error "-std=c++11" #define lowbit(x) (x&(-x)) #define max(x,y) (x>=y?x:y) #define min(x,y) (x<=y?x:y) #define MAX 100000000000000000 #define MOD 1000000007 #define pi acos(-1.0) #define ei exp(1) #define PI 3.1415926535897932384626433832 #define ios() ios::sync_with_stdio(true) #define INF 0x3f3f3f3f #define mem(a) (memset(a,0,sizeof(a))) typedef long long ll; int fa[100005]; ll n,k; struct f{ ll x,y,z; int id; }edge[100005]; struct node{ int u,v; ll dis; bool operator<(const node &a) const{ return a.dis>dis; } }e[400005]; int find(int x){ return fa[x]=(fa[x]==x?x:find(fa[x])); } bool cmp_xyz(f a,f b){//自定義排序 return a.x+a.y+a.z<b.x+b.y+b.z; } bool cmp_xy(f a,f b){ return a.x+a.y<b.x+b.y; } bool cmp_xz(f a,f b){ return a.x+a.z<b.x+b.z; } bool cmp_yz(f a,f b){ return a.z+a.y<b.z+b.y; } int main(){ scanf("%lld%lld",&n,&k); for(int i=0;i<n;i++){ scanf("%lld%lld%lld",&edge[i].x,&edge[i].y,&edge[i].z); edge[i].id=i+1; } for(int i=1;i<=n;i++) fa[i]=i; int ans=0; sort(edge,edge+n,cmp_xyz); for(int i=1;i<n;i++) e[ans++]=(node){edge[i].id,edge[i-1].id,edge[i].x+edge[i].y+edge[i].z-edge[i-1].x-edge[i-1].y-edge[i-1].z}; sort(edge,edge+n,cmp_xy); for(int i=1;i<n;i++) e[ans++]=(node){edge[i].id,edge[i-1].id,edge[i].x+edge[i].y-edge[i-1].x-edge[i-1].y}; sort(edge,edge+n,cmp_xz); for(int i=1;i<n;i++) e[ans++]=(node){edge[i].id,edge[i-1].id,edge[i].x+edge[i].z-edge[i-1].x-edge[i-1].z}; sort(edge,edge+n,cmp_yz); for(int i=1;i<n;i++) e[ans++]=(node){edge[i].id,edge[i-1].id,edge[i].z+edge[i].y-edge[i-1].z-edge[i-1].y}; int pos=n-1; sort(e,e+ans); ll inf=0; for(int i=0;i<ans && pos>0;i++){//最小生成樹kruskal寫法 int x=find(e[i].u); int y=find(e[i].v); if(x!=y){ inf+=e[i].dis; fa[x]=y; pos--; } } printf("%lld\n",inf*k); return 0; }