TZOJ 挑战题库随机训练05
A.Rational Approximation回到顶部
题意
给一个m+n(10)位多项式f=f0+f1x+f2x^2...,求一个最多n-1位多项式q和最多m-1位多项式p,使得q*f-p得到的最低项的指数为n+m-1,系数为1
题解
大概就是设一个多项式q,然后q*f,高斯消元解出q,最后计算得到p,复杂度O(10^3)
代码
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 #include<queue> 5 #include<string.h> 6 using namespace std; 7 8 #define LL long long 9 class rat 10 { 11 public: 12 LL num,den; 13 rat() { 14 num=0;den=1; 15 }; 16 rat(LL n,LL d){ 17 bool pos=true; 18 if(d<0){ 19 d=-d;pos=!pos; 20 } 21 if(n<0){ 22 n=-n;pos=!pos; 23 } 24 LL fac=__gcd(n,d); 25 num=n/fac; 26 den=d/fac; 27 if(!pos)num=-num; 28 }; 29 rat add(rat rhs){ 30 LL newNum=num*rhs.den+den*rhs.num; 31 LL newDen=den*rhs.den; 32 rat ans(newNum,newDen); 33 return ans; 34 }; 35 rat sub(rat rhs){ 36 LL newNum=num*rhs.den-den*rhs.num; 37 LL newDen=den*rhs.den; 38 rat ans(newNum,newDen); 39 return ans; 40 }; 41 rat mul(rat rhs){ 42 LL newNum=num*rhs.num; 43 LL newDen=den*rhs.den; 44 rat ans(newNum,newDen); 45 return ans; 46 }; 47 rat div(rat rhs){ 48 LL newNum=num*rhs.den; 49 LL newDen=den*rhs.num; 50 rat ans(newNum,newDen); 51 return ans; 52 }; 53 void print(){ 54 if(num==0)cout<<'0'; 55 else if(den==1)cout<<num; 56 else cout<<num<<'/'<<den; 57 } 58 }; 59 60 rat operator+(rat a,rat b){return a.add(b);}; 61 rat operator-(rat a,rat b){return a.sub(b);}; 62 rat operator*(rat a,rat b){return a.mul(b);}; 63 rat operator/(rat a,rat b){return a.div(b);}; 64 ostream& operator<<(ostream &out, rat a){a.print();return out;}; 65 66 const int N=15; 67 68 rat q[N],p[N],f[N],a[N][N],b[N]; 69 70 int n,m; 71 void printarray()//debug 72 { 73 for(int i=0; i<n; i++) { 74 for(int j=0; j<n; j++) 75 cout << a[i][j] << ' '; 76 cout<<b[i]; 77 cout << endl; 78 } 79 cout<<endl; 80 } 81 void Gauss(){ 82 for(int i=0;i<n-1;i++){ 83 int j=i; 84 while(a[i][j].num==0)j++; 85 if(j!=i){ 86 rat temp=b[j];b[j]=b[i];b[i]=temp; 87 for(int k=0;k<n;k++){ 88 temp=a[j][k];a[j][k]=a[i][k];a[i][k]=temp; 89 } 90 } 91 for(int k=i+1;k<n;k++){ 92 rat fact=a[k][i]/a[i][i]; 93 for(int l=i;l<n;l++){ 94 a[k][l]=a[k][l]-a[i][l]*fact; 95 } 96 b[k]=b[k]-b[i]*fact; 97 } 98 //printarray(); 99 } 100 q[n-1]=b[n-1]/a[n-1][n-1]; 101 for(int i=n-2;i>=0;i--){ 102 q[i]=b[i]; 103 for(int j=i+1;j<n;j++)q[i]=q[i]-a[i][j]*q[j]; 104 q[i]=q[i]/a[i][i]; 105 } 106 } 107 void pr(rat *s,int r){ 108 int out=0; 109 for(int i=0;i<r;i++){ 110 if(s[i].num==0)continue; 111 if(out==0)out=1; 112 else cout<<" "; 113 cout<<"("<<s[i]<<","<<i<<")"; 114 } 115 if(out==0)cout<<"(0,0)"; 116 cout<<'\n'; 117 } 118 int main(){ 119 int ca=0; 120 while(cin>>m>>n,m||n){ 121 if(ca++)cout<<'\n'; 122 for(int i=0;i<m+n;i++)cin>>f[i].num,f[i].den=1; 123 //n*n 124 //a x^n+m-1 x^n+m-2 .... x^0 125 //b x^n+m-1 x^n+m-2 .... x^0 126 for(int i=0;i<n;i++){ 127 for(int j=0;j<n;j++){ 128 if(m+j-i>=0){ 129 //printf("i=%d n-j-1=%d f[%d]=%lld\n",i,n-j-1,m+j-i,f[m+j-i]); 130 a[i][n-j-1]=f[m+j-i]; 131 } 132 else{ 133 //printf("i=%d n-j-1=%d 0 1\n",i,n-j-1); 134 a[i][n-j-1].num=0; 135 a[i][n-j-1].den=1; 136 } 137 } 138 b[i].num=(i==0)?1:0; 139 b[i].den=1; 140 //printf("i=%d num=%lld\n",i,b[i]); 141 } 142 Gauss(); 143 //for(int i=0;i<n;i++) 144 // q[i].print(),printf(" "); 145 for(int i=0;i<m;i++)p[i].num=0,p[i].den=1; 146 for(int i=0;i<n+m;i++) 147 for(int j=0;j<n;j++) 148 if(i+j<m) 149 p[i+j]=p[i+j]+f[i]*q[j]; 150 pr(p,m);pr(q,n); 151 } 152 return 0; 153 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=55; 4 struct P { 5 int x,y,id; 6 }; 7 int a[N][N],f[N]; 8 pair<int,int> x[N],y[N]; 9 pair<int,int> cal(pair<int,int> a) { 10 int x=a.first,y=a.second,t=__gcd(abs(x),abs(y)); 11 if(y<0) x=-x,y=-y; 12 return {x/t,y/t}; 13 } 14 pair<int,int> add(pair<int,int> a,pair<int,int> b) { 15 int x=a.first,y=a.second,xx=b.first,yy=b.second; 16 return cal({x*yy+xx*y,y*yy}); 17 } 18 void Gauss(int equ,int var) { 19 for(int i=0;i<=var;i++) x[i]={0,1}; 20 for(int col=0,row=0;row<equ&&col<var;row++,col++) { 21 int maxRow=row; 22 for(int i=row+1;i<equ;i++) { 23 if(abs(a[i][col])>abs(a[maxRow][col])) { 24 maxRow=i; 25 } 26 } 27 if(maxRow!=row){ 28 for(int j=row;j<var+1;j++) 29 swap(a[row][j],a[maxRow][j]); 30 } 31 if(a[row][col]==0){ 32 row--; 33 continue; 34 } 35 for(int i=row+1;i<equ;i++){ 36 if(!a[i][col]) continue; 37 int x=abs(a[i][col]),y=abs(a[row][col]); 38 int lcm=x/__gcd(x,y)*y,ta=lcm/x,tb=lcm/y; 39 if(a[i][col]*a[row][col]<0) tb=-tb; 40 for(int j=col;j<var+1;j++) { 41 a[i][j]=a[i][j]*ta-a[row][j]*tb; 42 } 43 } 44 } 45 for(int i=var-1;i>=0;i--){ 46 pair<int,int> tmp={a[i][var],1}; 47 for(int j=i+1;j<var;j++){ 48 if(!a[i][j]) continue; 49 tmp=add(tmp,{-a[i][j]*x[j].first,x[j].second}); 50 } 51 x[i]=cal({tmp.first,tmp.second*a[i][i]}); 52 } 53 } 54 void prt(pair<int,int> x[],int n) { 55 vector<P> A; 56 for(int i=0;i<n;i++) { 57 if(x[i].first) A.push_back({x[i].first,x[i].second,i}); 58 } 59 int sz=A.size(); 60 if(!sz) { 61 printf("(0,0)\n"); 62 return; 63 } 64 for(int i=0;i<sz;i++) { 65 if(A[i].y!=1) printf("(%d/%d,%d)%c",A[i].x,A[i].y,A[i].id,i==sz-1?'\n':' '); 66 else printf("(%d,%d)%c",A[i].x,A[i].id,i==sz-1?'\n':' '); 67 } 68 } 69 int main() { 70 int n,m,o=0; 71 while(~scanf("%d%d",&n,&m),n||m) { 72 if(o) printf("\n");++o; 73 for(int i=0;i<n+m;i++) scanf("%d",&f[i]); 74 for(int i=0;i<m;i++) { 75 for(int j=0;j<m;j++) { 76 a[i][j]=f[i-j+n]; 77 } 78 a[i][m]=(i==m-1?1:0); 79 } 80 Gauss(m,m); 81 for(int i=0;i<n+2*m;i++) y[i]={0,1}; 82 for(int i=0;i<n+m;i++) { 83 for(int j=0;j<m;j++) { 84 y[i+j]=add(y[i+j],{f[i]*x[j].first,x[j].second}); 85 } 86 } 87 prt(y,n),prt(x,m); 88 } 89 return 0; 90 }
B.An Old Stone Game回到顶部
题意
给一棵树N(200)个节点,每次在一个叶子节点放1颗石头,如果一个节点的所有儿子都有石头,那么在当前节点放一个石头,儿子的石头收回,丢掉所有儿子,问最少需要多少个石头才能使得根节点1有石头
题解
考虑一下,如果节点u的儿子有v1,v2,v3,v1需要3颗石头,v2需要6颗石头,v3需要3颗石头
排序一下,得到3,3,6,size为3,那么节点u可以放的石头数=max(vec[i]+size-i-1)
得到3+3-0-1,3+3-1-1,6+3-2-1最大值为6,复杂度O(nlogn)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=205; 5 vector<int>G[N]; 6 int dp[N]; 7 void dfs(int u){ 8 if(G[u].size()==0){ 9 dp[u]=1; 10 return; 11 } 12 vector<int>vec; 13 for(int i=0;i<G[u].size();i++){ 14 dfs(G[u][i]); 15 vec.push_back(dp[G[u][i]]); 16 } 17 sort(vec.begin(),vec.end()); 18 int ans=0,up=vec.size(); 19 for(int i=0;i<up;i++)ans=max(ans,vec[i]+up-i-1); 20 dp[u]=ans; 21 } 22 int main(){ 23 int t; 24 scanf("%d",&t); 25 while(t--){ 26 int n,k,x; 27 scanf("%d",&n); 28 for(int i=1;i<=n;i++)G[i].clear(); 29 for(int i=1;i<=n;i++){ 30 scanf("%*d%d",&k); 31 for(int j=1;j<=k;j++){ 32 scanf("%d",&x); 33 G[i].push_back(x); 34 } 35 } 36 dfs(1); 37 printf("%d\n",dp[1]); 38 } 39 return 0; 40 }
C.Repetition-Free Numbers回到顶部
题意
给一个整数n,求一个大于n的且位数都不相同的最小值
题解
一看道题目就会了,直接搜索+剪枝,如果不满足直接return,复杂度O(<<9!)
注意:得搜两次,一次是位数相同,一次是位数多
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 #define LL long long 5 int val,samep; 6 bool vis[10]; 7 void dfs(LL sum,int p){ 8 if(p>9)return; 9 if(sum>val){ 10 printf("%lld",sum); 11 exit(0); 12 } 13 for(int i=1;i<=9;i++){ 14 if(!vis[i]){ 15 vis[i]=1; 16 dfs(sum*10+i,p+1); 17 vis[i]=0; 18 } 19 } 20 } 21 void dfs1(LL sum,int p){ 22 //printf("%lld p=%d\n",sum,p); 23 if(p>samep-1)return; 24 if(sum>val){ 25 printf("%lld",sum); 26 exit(0); 27 } 28 for(int i=1;i<=9;i++){ 29 if(!vis[i]){ 30 vis[i]=1; 31 dfs1(sum*10+i,p+1); 32 vis[i]=0; 33 } 34 } 35 } 36 int main(){ 37 scanf("%d",&val); 38 if(val>=987654321)printf("0\n"); 39 else{ 40 int k=val; 41 int v[10]; 42 samep=0; 43 do{ 44 v[samep++]=k%10; 45 k/=10; 46 }while(k); 47 //same 48 for(int i=v[samep-1];i<=9;i++){ 49 vis[i]=1; 50 dfs1(i,0); 51 vis[i]=0; 52 } 53 dfs(0,0); 54 } 55 return 0; 56 }
D.Polynomial Showdown回到顶部
题意
给一个9位多项式,要求格式化后输出
题解
直接模拟,注意几个点,+-1,+-1在首位,+-1在最后,复杂度O(9)
坑:全0输出0
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int a[10]; 5 int main(){ 6 //freopen("1.in","r",stdin); 7 while(scanf("%d",&a[0])!=EOF){ 8 for(int i=1;i<=8;i++)scanf("%d",&a[i]); 9 //for(int i=0;i<=8;i++)printf("%d ",a[i]); 10 //puts(""); 11 vector< pair<int,int> >vec;//1x^2 12 if(a[8]!=0)vec.push_back({a[8],0}); 13 for(int i=7,x=1;i>=0;i--,x++){ 14 if(a[i]==0)continue; 15 vec.push_back({a[i],x}); 16 } 17 int o=0; 18 for(int i=vec.size()-1;i>=0;i--){ 19 int x=vec[i].first,exp=vec[i].second; 20 if(o==0){ 21 if(exp==0)printf("%d",x); 22 else if(exp==1){ 23 if(x==1)printf("x"); 24 else if(x==-1)printf("-x"); 25 else printf("%dx",x); 26 } 27 else if(abs(x)==1){ 28 if(x==1)printf("x^%d",exp); 29 else printf("-x^%d",exp); 30 } 31 else printf("%dx^%d",x,exp); 32 o=1; 33 }else{ 34 if(x>=1){ 35 if(exp==0)printf(" + %d",x); 36 else if(exp==1){ 37 if(x==1)printf(" + x"); 38 else printf(" + %dx",x); 39 } 40 else if(x==1)printf(" + x^%d",exp); 41 else printf(" + %dx^%d",x,exp); 42 }else{ 43 if(exp==0)printf(" - %d",abs(x)); 44 else if(exp==1){ 45 if(x==-1)printf(" - x"); 46 else printf(" - %dx",abs(x)); 47 } 48 else if(x==-1)printf(" - x^%d",exp); 49 else printf(" - %dx^%d",abs(x),exp); 50 } 51 } 52 } 53 //全0 54 if(o==0)printf("0"); 55 puts(""); 56 } 57 return 0; 58 }
E.WERTYU回到顶部
题意
给一个键盘,输入一个字母你输出它左边的一个字母
题解
把对应答案存在字符串里,复杂度O(44len)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 string s1,s2; 4 int main(){ 5 s1="1234567890-=WERTYUIOP[]\\SDFGHJKL;'XCVBNM,./"; 6 s2="`1234567890-QWERTYUIOP[]ASDFGHJKL;ZXCVBNM,."; 7 //cout<<s1<<endl; 8 //cout<<s2<<endl; 9 string s; 10 while(getline(cin,s)){ 11 for(int i=0;s[i];i++){ 12 if(s[i]==' '){ 13 cout<<" "; 14 continue; 15 } 16 for(int j=0;j<s1[j];j++) 17 if(s[i]==s1[j]){ 18 cout<<s2[j];break; 19 } 20 } 21 cout<<"\n"; 22 } 23 return 0; 24 }
F.Power Strings回到顶部
题意
给一个字符串,要求你找一个子串的k次方等于这个字符串,输出最大的k
题解
kmp中的next数组,next[i]表示[0,i)前缀和后缀相同的最大长度
next[n]表示[0,n+1)字符串的循环节长度为n-next[n],那么只需要n/(n-next[n])
注意如果不能整除,那么不存在循环节,输出1,复杂度O(len)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=1e6+5; 5 char s[N]; 6 int n,nex[N]; 7 void Getnex(){ 8 int i=0,j=-1; 9 nex[i]=j; 10 while(i<n){ 11 while(j!=-1&&s[i]!=s[j])j=nex[j]; 12 nex[++i]=++j; 13 } 14 } 15 int main(){ 16 while(scanf("%s",s)!=EOF){ 17 if(s[0]=='.')break; 18 n=strlen(s); 19 Getnex(); 20 //for(int i=0;i<=n;i++)printf("i=%d nex=%d\n",i,nex[i]); 21 if(n%(n-nex[n])==0)printf("%d\n",n/(n-nex[n])); 22 else printf("1\n"); 23 } 24 return 0; 25 }
G.三国游戏回到顶部
题意
N(500)个人,每两个人有一个默契值,并且两两默契值都不相同,小涵每次选一个人,电脑每次选剩下人中与刚才小涵选的人默契值最大的人,最后小涵和电脑拿出两个人,默契值高的获胜
题解
题意一大堆,稍微想想就可以知道,由于两两默契值不同,那么小涵每次选一个人,电脑选一个最大默契的,这时候小涵只需要选第二大默契的,那么后面再怎么选,都不会使答案更好,复杂度O(n^2)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=505; 5 int G[N][N]; 6 int main(){ 7 int n,x,f=0,sum=-1; 8 scanf("%d",&n); 9 for(int i=1;i<n;i++){ 10 for(int j=i+1;j<=n;j++){ 11 scanf("%d",&G[i][j]); 12 G[j][i]=G[i][j]; 13 } 14 } 15 for(int i=1;i<=n;i++){ 16 int fimax=-1,semax=-1; 17 for(int j=1;j<=n;j++){ 18 if(G[i][j]>fimax)semax=fimax,fimax=G[i][j]; 19 else if(G[i][j]>semax)semax=G[i][j]; 20 } 21 if(semax!=-1&&semax>sum)sum=semax,f=1; 22 } 23 if(sum==-1||n==2)printf("0"); 24 else printf("1\n%d",sum); 25 return 0; 26 }
H.Castle Walls回到顶部
题意
n+m(500+500)个人,投钩子勾n+m的城墙,问有多少个钩子相交
题解
也是一看就会了,这种题比较套路
按id排个序后,搞个树状数组,树状数组查出来的是[1,x]中比x小的个数,复杂度O(nlogn)
PS:background?根本不需要看
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int N=60005; 5 int sum[N],n,m; 6 struct node{ 7 int u,v; 8 bool operator<(const node &d)const{ 9 return u<d.u; 10 } 11 }a[N]; 12 int lowbit(int x){ 13 return x&(-x); 14 } 15 void add(int p){ 16 for(int i=p;i<=n;i+=lowbit(i))sum[i]++; 17 } 18 int query(int p){ 19 int ans=0; 20 for(int i=p;i>0;i-=lowbit(i))ans+=sum[i]; 21 return ans; 22 } 23 int main(){ 24 int t,ca=1; 25 scanf("%d",&t); 26 while(t--){ 27 memset(sum,0,sizeof sum); 28 scanf("%d%d",&n,&m); 29 n+=m; 30 for(int i=1;i<=n;i++)scanf("%d%d",&a[i].u,&a[i].v); 31 sort(a+1,a+1+n); 32 int ans=0; 33 for(int i=1;i<=n;i++){ 34 //printf("i=%d %d %d %d\n",i,i-1-query(a[i].v-1),a[i].u,a[i].v); 35 ans+=(i-1-query(a[i].v-1)); 36 add(a[i].v); 37 } 38 printf("Scenario #%d:\n%d\n\n",ca++,ans); 39 } 40 return 0; 41 }
I.Text Reverse回到顶部
题意
给一句话,把每个单词反过来输出
题解
模拟,按空格结束,再把得到的字符串翻转,复杂度O(len)
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int t; 5 string s; 6 int main(){ 7 cin>>t;cin.get(); 8 while(t--){ 9 getline(cin,s); 10 string p; 11 s=s+" "; 12 for(int i=0;s[i];i++){ 13 if(s[i]==' '){ 14 reverse(p.begin(),p.end()); 15 cout<<p; 16 if(i<s.size()-1)cout<<" "; 17 p=""; 18 } 19 else p=p+s[i]; 20 } 21 cout<<endl; 22 } 23 return 0; 24 }
J.Entertainment回到顶部
题意
N*N(1000)的图,查询每次删除1个点及其附近相同的所有点,然后图往左移,再往下移,得到新图,一直查询k次
题解
题意一大堆,其实只要看4幅图
做法很简单,模拟,每次广搜删点,左移,下移,下移的同时记录一下新图从哪一行开始,复杂度O(kn^2)
坑:不是在一开始的图上广搜,每次图会变
PS:感觉这个复杂度有点奇怪,也不知道k的大小,但是过了哈哈
代码
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 #include<queue> 5 #include<string.h> 6 using namespace std; 7 8 const int N=1005; 9 string s[N]; 10 int n,m,nu; 11 int dx[]={0,0,1,-1}; 12 int dy[]={1,-1,0,0}; 13 queue<int>qx,qy; 14 bool vis[N][N]; 15 void bfs(int sx,int sy){ 16 memset(vis,0,sizeof vis); 17 while(!qx.empty())qx.pop(); 18 while(!qy.empty())qy.pop(); 19 qx.push(sx),qy.push(sy); 20 char sch=s[sx][sy];s[sx][sy]=' '; 21 vis[sx][sy]=1; 22 while(!qx.empty()){ 23 int ux=qx.front();qx.pop(); 24 int uy=qy.front();qy.pop(); 25 for(int i=0;i<4;i++){ 26 int vx=ux+dx[i]; 27 int vy=uy+dy[i]; 28 if(vx>=0&&vx<n&&vy>=0&&vy<m&&!vis[vx][vy]&&s[vx][vy]==sch){ 29 qx.push(vx);qy.push(vy); 30 s[vx][vy]=' '; 31 vis[vx][vy]=1; 32 } 33 } 34 } 35 } 36 void L(){ 37 int mxr=0; 38 for(int i=0;i<n;i++){ 39 int p=0,q=0,r=0; 40 while(q<m){ 41 if(s[i][q]!=' '){ 42 swap(s[i][p],s[i][q]); 43 p++;r=p; 44 } 45 q++; 46 } 47 mxr=max(mxr,r); 48 } 49 m=mxr; 50 } 51 void D(){ 52 int miu=0x3f3f3f3f; 53 for(int i=0;i<m;i++){ 54 int p=n-1,q=n-1,u=n-1; 55 while(q>=0){ 56 if(s[q][i]!=' '){ 57 swap(s[p][i],s[q][i]); 58 u=p;p--; 59 } 60 q--; 61 } 62 miu=min(miu,u); 63 } 64 nu=miu; 65 } 66 void Pr(){ 67 for(int i=nu;i<n;i++){ 68 for(int j=0;j<m;j++) 69 cout<<s[i][j]; 70 cout<<'\n'; 71 } 72 } 73 int main(){ 74 ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 75 int ca=0; 76 while(getline(cin,s[0])){ 77 m=s[0].size(); 78 int k=0; 79 for(n=1;;n++){ 80 getline(cin,s[n]); 81 if(s[n][0]>='0'&&s[n][0]<='9'){ 82 for(int i=0;s[n][i];i++)k=k*10+s[n][i]-'0'; 83 break; 84 } 85 } 86 //? 87 //cout<<"k="<<k<<endl; 88 //for(int i=0;i<n;i++)cout<<s[i]<<endl; 89 nu=0; 90 for(int i=0;i<k;i++){ 91 int r,c; 92 cin>>r>>c; 93 r--,c--; 94 bfs(r+nu,c);L();D(); 95 } 96 cout<<"Test case #"<<++ca<<":\n"; 97 Pr(); 98 // 99 if(k)cin.get(); 100 //for(int i=0;i<n;i++)s[i].clear(); 101 } 102 return 0; 103 }