暑假训练场
A(UVAL6182)、
凯神看了敲掉的题目,还没有看过
1 #include <iostream>
2 #include <memory.h>
3
4 using namespace std; 5
6 const int MAX = 256; 7
8 bool Solve(int x, int y); 9 bool Check(int m, int n, int p, int q); 10
11 int main() 12 { 13 ios::sync_with_stdio(false); 14 int N, x, y; 15 while(cin >> N) 16 { 17 for(int i = 1; i <= N; i++) 18 { 19 cin >> x >> y; 20 if((x * x + y * y != 0) && Solve(x, y)) { cout << "P" << endl; } 21 else { cout << "C" << endl; } 22 } 23 } 24 return 0; 25 } 26
27 bool Solve(int x, int y) 28 { 29 int ans = 0; 30 for(int i = -MAX; i <= MAX; i++) 31 { 32 for(int j = -MAX; j <= MAX; j++) 33 { 34 if(i * i + j * j == 0) { continue; } 35 if(Check(i, j, x, y)) 36 { ans++; } 37 } 38 } 39 return ans == 8; 40 } 41
42 bool Check(int m, int n, int p, int q) 43 { 44 int x = m * m + n * n; 45 int y = m * p + n * q, z = m * q - n * p; 46 int a = y / x, b = z / x; 47 int c = a * a + b * b, d = p * p + q * q; 48 if(y % x != 0 || z % x != 0) { return false; } 49 return x * c == d; 50 }
B(UVAL6183)、
一道关于三元线性方程组求解的问题,对于给定的文本,每一行前导点'.'由之前的文本中未匹配的大中小括号决定,是关于三个括号的线性关系,因此可以由给定的文本情况列出一系列线性方程,获取三个系数的信息,再由此判断给定的文本每行分别需要加上多少个前导点。
一开始由于前面先做的D题,我研究了高斯消元,队友看完这题就告诉我这题也是高消,于是我就按高消的做法做,然而在测试各种样例的时候发现了各种问题,然后重新确定了做法,由于三个系数都已经固定了范围是1到20间的正整数,所以完全可以20*20*20的循环枚举每一组解,去匹配所有<=10个方程,记录下所有可行解,然后再用这些解依次对需要输出的每一行计算一次需要输出的点数,如果所有可行解求出的点数都是一样的,那么这个式子的点数就是确定的,可以输出,否则就输出-1.
1 #include<stdio.h>
2 #include<string.h>
3 #include<math.h>
4 #include<algorithm>
5 using namespace std; 6 #define eps 1e-5
7
8 const int maxn=5; 9
10 int num[25]; 11 int x[25],y[25],z[25],ansx[25],ansy[25],ansz[25],ans[5]; 12 char s[100]; 13 int anss[8005][3]; 14
15 int main(){ 16 int p,q; 17 while(scanf("%d%d",&p,&q)!=EOF&&(p+q)){ 18 int i,j,k; 19 memset(ans,0,sizeof(ans)); 20 memset(num,0,sizeof(num)); 21 for(i=0;i<p+q;i++){ 22 x[i+1]=x[i]; 23 y[i+1]=y[i]; 24 z[i+1]=z[i]; 25 scanf("%s",s); 26 bool f=1; 27 for(j=0;j<strlen(s);j++){ 28 if(f&&s[j]=='.'){ 29 num[i]++; 30 } 31 else f=0; 32 if(s[j]=='(')x[i+1]++; 33 if(s[j]==')')x[i+1]--; 34 if(s[j]=='[')y[i+1]++; 35 if(s[j]==']')y[i+1]--; 36 if(s[j]=='{')z[i+1]++; 37 if(s[j]=='}')z[i+1]--; 38 } 39 } 40 // for(i=0;i<p+q;i++)printf("%d %d %d %d\n",x[i],y[i],z[i],num[i]);
41 memset(ansx,0,sizeof(ansx)); 42 memset(ansy,0,sizeof(ansy)); 43 memset(ansz,0,sizeof(ansz)); 44 int c=0; 45 for(i=1;i<=20;i++){ 46 for(j=1;j<=20;j++){ 47 for(k=1;k<=20;k++){ 48 bool f=1; 49 for(int o=1;o<p&&f;o++){ 50 if(x[o]*i+y[o]*j+z[o]*k!=num[o])f=0; 51 } 52 if(f){ 53 ++c; 54 anss[c][0]=i; 55 anss[c][1]=j; 56 anss[c][2]=k; 57
58 ansx[i]=1; 59 ansy[j]=1; 60 ansz[k]=1; 61 } 62 } 63 } 64 } 65 int cnt=0; 66 for(i=1;i<=20;i++){ 67 if(ansx[i]){ 68 cnt++; 69 ans[0]=i; 70 } 71 } 72 if(cnt!=1)ans[0]=0; 73 cnt=0; 74 for(i=1;i<=20;i++){ 75 if(ansy[i]){ 76 cnt++; 77 ans[1]=i; 78 } 79 } 80 if(cnt!=1)ans[1]=0; 81 cnt=0; 82 for(i=1;i<=20;i++){ 83 if(ansz[i]){ 84 cnt++; 85 ans[2]=i; 86 } 87 } 88 if(cnt!=1)ans[2]=0; 89 /* for(i=0;i<=2;i++)printf("%d ",ans[i]); 90 printf("\n"); 91 */ for(i=p;i<p+q;i++){ 92 if((x[i]&&ans[0]==0)||(y[i]&&ans[1]==0)||(z[i]&&ans[2]==0)){ 93 bool f=1; 94 int res=0; 95 for(j=1;j<=c&&f;j++){ 96 if(j==1)res=x[i]*anss[j][0]+y[i]*anss[j][1]+z[i]*anss[j][2]; 97 else if(res!=x[i]*anss[j][0]+y[i]*anss[j][1]+z[i]*anss[j][2]){ 98 f=0; 99 } 100 } 101 if(f)printf("%d",res); 102 else printf("-1"); 103 } 104 else printf("%d",x[i]*(int)ans[0]+y[i]*(int)ans[1]+z[i]*(int)ans[2]); 105 if(i==p+q-1)printf("\n"); 106 else printf(" "); 107 } 108 } 109 return 0; 110 }
C(UVAL6184)、
凯神刻盘做的矩阵快速幂,并没有看,貌似T了好几发,结果把longlong改int就过了
1 #include <stdio.h>
2 #include <memory.h>
3
4 const int MAX = 64; 5
6 struct Matrix 7 { 8 Matrix() { } 9
10 Matrix(int R, int C, int M) : R(R), C(C), M(M) { } 11
12 void Clear() 13 { memset(pData, 0, sizeof(pData)); } 14
15 void Init(int A, int B, int C) 16 { 17 for(int i = 1; i < MAX; i++) 18 { 19 pData[i][i - 1] = A; 20 pData[i][i] = B; 21 pData[i][i + 1] = C; 22 } 23 } 24
25 Matrix operator + (Matrix& x) const
26 { 27 Matrix ans(R, C, M); 28 for(int i = 1; i <= R; i++) 29 { 30 for(int j = 1; j <= C; j++) 31 { 32 ans.pData[i][j] = (pData[i][j] + x.pData[i][j]) % M; 33 } 34 } 35 return ans; 36 } 37
38 Matrix operator * (Matrix& x) const
39 { 40 Matrix Tmp(R, x.C, M); 41 Tmp.Clear(); 42 for(int k = 1; k <= C; k++) 43 { 44 for(int i = 1; i <= Tmp.R; i++) 45 { 46 for(int j = 1; j <= Tmp.C; j++) 47 { 48 Tmp.pData[i][j] = (Tmp.pData[i][j] + (pData[i][k] * x.pData[k][j]) % M) % M; 49 } 50 } 51 } 52 return Tmp; 53 } 54
55 Matrix operator ^ (int x) const
56 { 57 Matrix ans(R, R, M), Tmp(R, R, M); 58 memcpy(Tmp.pData, pData, sizeof(Tmp.pData)); 59 ans.Clear(); 60 for(int i = 1; i <= ans.R; i++) 61 { ans.pData[i][i] = 1; } 62 while(x) 63 { 64 if(x & 1) { ans = ans * Tmp; } 65 x >>= 1; 66 Tmp = Tmp * Tmp; 67 } 68 return ans; 69 } 70
71 int R, C, M; 72 int pData[MAX][MAX]; 73 }; 74
75 int S[MAX]; 76 int N, M, A, B, C, T; 77
78 int main() 79 { 80 while(scanf("%d%d%d%d%d%d", &N, &M, &A, &B, &C, &T) != EOF) 81 { 82 if(N == 0 && M == 0 && A == 0 && B == 0 && C == 0 && T == 0) { break; } 83 Matrix X(N, N, M); 84 X.Clear(); 85 X.Init(A, B, C); 86 X = X ^ T; 87 for(int i = 1; i <= N; i++) 88 { scanf("%d", &S[i]); } 89 for(int i = 1; i <= N; i++) 90 { 91 int ans = 0; 92 for(int j = 1; j <= N; j++) 93 { 94 ans += X.pData[i][j] * S[j]; 95 ans %= M; 96 } 97 printf("%d", ans); 98 if(i != N) { printf(" "); } 99 } 100 printf("\n"); 101 } 102 return 0; 103 }
D(UVAL6185)、
高斯消元,做的时候还不会高消,拿了本红书看高消模板,然后就敲了,纠结了好久。这题就是有d个未知量的d+3个线性方程的解,其中有一个是错误的,要求出是哪一个解,明白高消模板后,由于方程最多只有7个,所以我就准备直接暴力枚举,选两个作为备选方程,其余的式子可以解出一组解,由于系数分别是0~d+2的幂次,所以所有的方程都不可能出现系数成比例的情况,所以一定能解出一组特解而不是通解,然后用求出的解判断剩下两组方程是否正确,如果一个正确一个错误,那么错误的那个方程就是要求的。
虽然方向正确,但是卡在了精度上,我一开始按题意定1e-6,发现后面的解被舍去了,于是一步步加大精度,一度开到1e-13都并没有成功,最后换成1e-5就过了,过大的精度把误差正好1e-6的解卡掉了```
#include<stdio.h> #include<string.h> #include<math.h> #include<algorithm>
using namespace std; #define eps 1e-5
const int maxn=10; int n; double ans[10]; bool l[10]; double num[10]; inline void solve(double a[][maxn]){ int res=0,r=0; for(int i=0;i<n;i++){ l[i]=0; } for(int i=0;i<n;i++){ for(int j=r;j<n;j++){ if(fabs(a[j][i])>eps){ for(int k=i;k<=n;k++){ swap(a[j][k],a[r][k]); } break; } } if(fabs(a[r][i])<eps){ res++; continue; } for(int j=0;j<n;j++){ if(j!=r&&fabs(a[j][i])>eps){ double tmp=a[j][i]/a[r][i]; for(int k=i;k<=n;k++){ a[j][k]-=tmp*a[r][k]; } } } l[i]=1,++r; } for(int i=0;i<n;i++){ if(l[i]){ for(int j=0;j<n;j++){ if(fabs(a[j][i])>0){ ans[i]=a[j][n]/a[j][i]; } } } } } int d; bool judge(int x){ double ans1=0,ans2=num[x]; double tmp=1; for(int i=d;i>=0;i--){ ans1+=ans[i]*tmp; tmp*=x; } // if(x==0)printf("0 %lf %lf\n",ans1,ans2);
if(fabs(ans1-ans2)<eps)return 1; else return 0; } double a[10][maxn]; int main(){ while(scanf("%d",&d)!=EOF&&d){ n=d+1; int i,j; bool f=1; for(i=0;i<=d+2;i++){ scanf("%lf",&num[i]); } int k; for(i=0;i<d+2&&f;i++){ for(j=i+1;j<=d+2&&f;j++){ int cnt=0; for(k=0;k<=d+2;k++){ if(k!=i&&k!=j){ a[cnt][d+1]=num[k]; double num1=k; a[cnt][d]=1; for(int p=d-1;p>=0;p--){ a[cnt][p]=num1; num1*=k; } cnt++; } } /* if(i==0&&j==1){ for(int q=0;q<=n;q++){ for(int w=0;w<=n;w++){ printf("%lf ",a[q][w]); } printf("\n"); } } */ solve(a); bool f1=judge(i),f2=judge(j); /* if(i==0&&j==1){ printf("%d %d\n",judge(0),f2); for(int q=0;q<=n;q++)printf("%lf ",ans[q]); printf("\n"); } */ if(f1!=f2){ if(f1)printf("%d\n",j); else printf("%d\n",i); f=0; } } } } return 0; }
E(UVAL6186)、
刻盘说是BFS套BFS,然而并没有敲掉就是这样```
F(UVAL6187)、
刻盘开场看的水题,就是给出两个数的差值,或者询问两个数的差值,裸的带权并查集
1 #include<stdio.h>
2 #include<string.h>
3 using namespace std; 4 typedef long long ll; 5
6 int fa[100005]; 7 ll num[100005]; 8 char s[10]; 9
10 void init(int n){ 11 for(int i=0;i<n;i++){fa[i]=i;num[i]=0;} 12 } 13
14 int find(int x){ 15 ll r=x,t1,t2,c=0; 16 while(r!=fa[r]){ 17 c+=num[r]; 18 r=fa[r]; 19 } 20 while(x!=r){ 21 t1=fa[x]; 22 t2=c-num[x]; 23 num[x]=c; 24 fa[x]=r; 25 c=t2; 26 x=t1; 27 } 28 return r; 29 } 30
31 int main(){ 32 int n,m; 33 while(scanf("%d%d",&n,&m)!=EOF&&(n+m)){ 34 int i,j,a,b,c; 35 init(n+3); 36 for(i=1;i<=m;i++){ 37 scanf("%s",s); 38 if(s[0]=='!'){ 39 scanf("%d%d%d",&a,&b,&c); 40 int x=find(a),y=find(b); 41 if(x!=y){ 42 fa[x]=y; 43 num[x]=num[b]+c-num[a]; 44 } 45 } 46 else if(s[0]=='?'){ 47 scanf("%d%d",&a,&b); 48 int x=find(a),y=find(b); 49 if(x!=y){ 50 printf("UNKNOWN\n"); 51 } 52 else printf("%lld\n",num[a]-num[b]); 53 } 54
55 } 56 } 57 return 0; 58 }
G(UVAL6188)、
据说是一道计算几何,然而比赛的时候并没有人看这题```估计相对较难吧```
H(UVAL6189)、
并没有看过```
I(UVAL6190)、
一道关于排版的题目,一段文本,每个单词有分别的字母数,然后每个字母占一格,一行固定格数,要求保证单词依次放入,行首行末单词顶格,单词之间必须要用空格隔开,问词间空格数的最大值最小是多少。
我开始看这题的时候凯神和刻盘已经讨论挺久了,意见倾向于二分答案,但是如何判断答案是否可行还没有想法,贪心据说不行,于是我觉得是dp来判定,但是的普通来说这里dp就会是O(n2)的算法,显然会T。补题的时候才听指点说是单调性优化成O(n)。我的做法是,对于每个可行的作为行开头的单词,拓展出下一个可行的开头单词,就是如果以这个单词为行首,那么到后面某个单词如果中间的空格平均下来 >=1 又 <= 枚举的答案,那么那个单词的就可以做为行末,也就是再之后的一个单词就可以作为行首。 ①由于是可行性dp,所以如果这个单词被判断可行,那么之后显然就不需要再判断了, ②而如果这个单词作为行末和行首单词之间需要的空格数比答案大,那么下一次枚举的行首单词一定更靠近该单词,那么中间的空格显然会更大,一定不可行,所以也不需要判断, ③而如果这个单词和行首单词之间需要的空格数平均下来<=1 ,那么对于这个行首单词就已经不需要再判断更后面的但是是否可以作为行末,因为放在同一行的话空格数会更小,就可以直接break出循环,所以总体就是类似两个指针分别从1到n的判断,即O(2n)。
1 #include<stdio.h>
2 #include<string.h>
3 #include<algorithm>
4 using namespace std; 5
6 int x[50005],s[50005]; 7 bool vis[50005]; 8 int w,n; 9
10 bool judge(int l){ 11 int i,j; 12 memset(vis,0,sizeof(vis)); 13 vis[1]=1; 14 int pos=2; 15 for(i=1;i<=n;i++){ 16 if(vis[i]){ 17 int sum2=s[n]-s[i-1],cnt2=n-i; 18 if(sum2+cnt2<=w){ 19 return 1; 20 } 21 bool f=1; 22 for(j=pos;j<=n;j++){ 23 int sum=s[j]-s[i-1],cnt=j-i; 24 if(sum+cnt>w)break; 25 if(sum+l*cnt>=w){ 26 vis[j+1]=1; 27 } 28 pos=j+1; 29 } 30 } 31 } 32 return 0; 33 } 34
35 int main(){ 36 while(scanf("%d%d",&w,&n)!=EOF&&(w+n)){ 37 int i,j; 38 memset(s,0,sizeof(s)); 39 for(i=1;i<=n;i++){ 40 scanf("%d",&x[i]); 41 s[i]=s[i-1]+x[i]; 42 } 43 // for(i=1;i<=n;i++)printf("%d ",s[i]); 44 // printf("\n");
45 int l=1,r=w; 46 while(l<=r){ 47 int mid=l+((r-l)>>1); 48 // printf("%d %d %d %d\n",l,r,mid,judge(mid)); 49 // if(mid==2)printf("%d\n",judge(mid));
50 if(judge(mid)){ 51 r=mid-1; 52 } 53 else l=mid+1; 54 } 55 printf("%d\n",l); 56 } 57 return 0; 58 }
J(UVAL6191)、
开场我从后往前看的题,所以一开始就看的这题,题目看到一半就取敲题目了,然后基本一路敲题调试到结束,所以这道题也就没有看了,貌似是个神题,总之是没有几个队做出来昂,然后就没有然后了```