劳动节的玩具。。
2016-05-04 18:35
337 查看
第一题 987654321 problem
水题,打个表找个规律,一瞬间就好了。。
第二题 Self-numbers 2
这道题蛮好的。。 一开始忽略了内存大小,在用哈希表做(把所有不符合的存入哈希表中),在第5组的时候出现了PE。。 PE。。 然后各种调试都PE。。 搜题解, 发现原来这题的位置不是从小到大的,而且可能有重复的位置,那就sort2遍好了。。 第5组爆内存。。 哈希值得问题吧。。 第6组超时。。
然后就知道了,这道题用哈希很膨胀。。
于是 看题解, 他们把这个方式叫做滚动数组。。 说白了,就是数组的重复使用,机智。
他们是这么做的:1。比如,当前的数字是 13 ,那么13 可以推出 13+1+3=17 不是,于是 我们知道了 13 后面的第 4 个数字不可取;
2。当前数子是999 那么就是他后面的 第 27 个数字不可取。
3。最大的数字是10的7次, 那么他的影响力最多是 7*9=63。 7是位数,9是每位的最大数。于是就可以开一个长度为 126 的数组,以 63 为更新节(最大影响力是63),滚来滚去(f1记录在63中的(我的这一波),f2记录我这一波(f1)对下一波的影响力);
这样既省内存又方便。。机智。。
第三题 Boxes
这道题一开始很自信,认为自己可以o(1)解决,失败了。。
但是,再想想一定可以o(1)解决的。。
这里给出模拟做法,因为有 *2 这个东西,而且数据最大才2的31次,最差的情况就是 31*31 因为每次移动31,运行了31组(log2 2的31次)。。(当然,这不是最差的,因为两者一定会逐渐接近)但是 900 这样的时间够了。。 实验证明50都可以。。数据水。。
第四题 Palindrome pairs
这个东西,以我目前的水平,还不能统一字符长度为1的情况。。
记录一下头尾的所有就好了。。
E 模拟大法好。。 先找到最近的一段,然后就可以玩了。。
F 还是模拟,排序一下就好了。。
G题 ,这道题 又是模拟,我发现了,在cf里面即使PE 了都没问题。。
不过我还是很认真的输出了。。
这道题运气好碰巧凑对了。。
值得注意的是下界的计算,反正我因为这个wa2发之后直接偷懒了。。
H Wall Painting
异或 这题不错,既然要算的是每一个组合后数的和(sum),
1。sum=第一位+第二位+第三位。。。第一位,第二位,第三位。。 他们之间是无关的。
2。这道题算的是所有东西的和,所以重复也没关系,用不到容斥,话说早上和友人讨论的32n微软面试题 应该容斥做是可行的吧。。(嘘)。。
这样就是一道简单的排列组合题目了。。
用int wa了。。 那就开 long long 吧
I Railway Tickets 这道题太有趣了,交了11次。。 因为终点可以在起点前面。。
简单的dp。。
J Ministry 这道题2刷的时候居然爆内存了。。 哇擦,我第一遍做的时候怎么可以那么机智,用数字表示如何走。。用字母果断爆炸了。。
一开始想到了B题的滚动数组,因为走到下一层,上一层就没用了。
原来这就是dp里面套dp,先左扫一遍,然后右边扫一遍。。 因为某个点,到底是从左走还是从右走,一切都是趋向于最小,所以先左先右没关系。。
K 题,,放一放,放一放,找规律,吃不消。。
现在可以了,根据我的手动模拟,首先来看“。。。。”这种情况,很明显2个点,然后看“。。。。。”这种情况,3个点。
于是 像这种1条的得出规律n/2+if(奇数)则1;
2*1的时候一个点 2*2 的时候1个点 2*3 的时候,我们找到规律,就是可以消去一条边 边成1*3的情况。。2*4 的情况我们可以照样消去3个点。。于是3就是关键。。这样我们就可以尽可能的去消除3 题目也就是水题了。。
L Gentlemen
身为大绅士的我,自然要华丽的做出啦。。。
感觉自己比网上题解写的好多了。。不过方法一样
用一个pre记录路径,dp来看有几条路。。并不用01背包的样子。。(反而觉得用了看不懂了)
M Broken line 这道题一开始没读清题目意思,觉得是任何图形(奇形怪状),用数学的向量做,然后爆炸啊,写不出来啊,分类太多了。
然后,搜题解,妈呀,人家为何呢么几个等号就出来了呢?原来是方形,方形,方形,一下子水了。。。
N Beat
数据小的可怜,dfs一下就好了。。
总算最后一题了。。
水题,打个表找个规律,一瞬间就好了。。
#include<cstdio> #include<iostream> using namespace std; int main() { /*for(long long i=1000;i<=0x7ffffffff;i++) { if((i*i)%1000000000==987654321) { cout<<i<<endl; } }*/ int n; cin>>n; if(n<=8) { cout<<'0'<<endl; } else if(n==9) { cout<<'8'<<endl; } else { cout<<"72"; while(n!=10) { printf("0"); n--; } printf("\n"); } return 0; }
第二题 Self-numbers 2
这道题蛮好的。。 一开始忽略了内存大小,在用哈希表做(把所有不符合的存入哈希表中),在第5组的时候出现了PE。。 PE。。 然后各种调试都PE。。 搜题解, 发现原来这题的位置不是从小到大的,而且可能有重复的位置,那就sort2遍好了。。 第5组爆内存。。 哈希值得问题吧。。 第6组超时。。
然后就知道了,这道题用哈希很膨胀。。
于是 看题解, 他们把这个方式叫做滚动数组。。 说白了,就是数组的重复使用,机智。
他们是这么做的:1。比如,当前的数字是 13 ,那么13 可以推出 13+1+3=17 不是,于是 我们知道了 13 后面的第 4 个数字不可取;
2。当前数子是999 那么就是他后面的 第 27 个数字不可取。
3。最大的数字是10的7次, 那么他的影响力最多是 7*9=63。 7是位数,9是每位的最大数。于是就可以开一个长度为 126 的数组,以 63 为更新节(最大影响力是63),滚来滚去(f1记录在63中的(我的这一波),f2记录我这一波(f1)对下一波的影响力);
这样既省内存又方便。。机智。。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<string> using namespace std; struct shu { int v; int loc; }who[5001]; int ans[5001]; bool f1[63],f2[63]; int cmp(shu a,shu b) { return a.v<b.v; } int main() { int n,k; scanf("%d%d",&n,&k); for(int i=0;i<k;i++) { scanf("%d",&who[i].v); who[i].loc=i; } sort(who,who+k,cmp); memset(f1,true,sizeof(f1)); memset(f2,true,sizeof(f2)); int num=0; int me=0; for(int i=1;i<=n;i++) { if(!(i%63)) { memcpy(f1,f2,sizeof(f2)); memset(f2,true,sizeof(f2)); } if(f1[i%63]) { num++; while(num==who[me].v) { ans[who[me].loc]=i; me++; } } int test=i; int add=0; while(test) { add=add+test%10; test=test/10; } if(i%63+add<63) { f1[i%63+add]=false; } else { f2[(i%63+add)%63]=false; } } printf("%d\n",num); for(int i=0;i<k;i++) { printf("%d",ans[i]); if(i!=n-1) { printf(" "); } else { printf("\n"); } } return 0; }
第三题 Boxes
这道题一开始很自信,认为自己可以o(1)解决,失败了。。
但是,再想想一定可以o(1)解决的。。
这里给出模拟做法,因为有 *2 这个东西,而且数据最大才2的31次,最差的情况就是 31*31 因为每次移动31,运行了31组(log2 2的31次)。。(当然,这不是最差的,因为两者一定会逐渐接近)但是 900 这样的时间够了。。 实验证明50都可以。。数据水。。
#include<cstdio> #include<iostream> using namespace std; int main() { int a,b; cin>>a>>b; int step=0; int flag=1; while(a&&b) { if(a<b) { int t=a; a=b; b=t; } a=a-b; b=b<<1; step++; if(step>50)//数据水。。。 { flag=0; break; } } if(!flag) { cout<<"-1"<<endl; } else { cout<<step<<endl; } return 0; }
第四题 Palindrome pairs
这个东西,以我目前的水平,还不能统一字符长度为1的情况。。
记录一下头尾的所有就好了。。
#include<cstdio> #include<iostream> #include<cstring> using namespace std; char a[2001]; int p[2001]; int q[2001]; int main() { scanf("%s",a); int len=strlen(a); for(int i=0;i<len;i++) { int id=i; int to=0; while(id+to<len&&id-to>=0&&a[id-to]==a[id+to]) { p[id-to]++; q[id+to]++; to++; } id=i; to=0; while(id-to-1>=0&&id+to<len&&a[id-to-1]==a[id+to]) { p[id-to-1]++; q[id+to]++; to++; } } long long ans=0; for(int i=0;i<len;i++) { long long test=0; for(int j=i+1;j<len;j++) { test=test+p[j]; } ans=ans+test*q[i]; } if(ans==0)//恩,真的不知道怎么合并到一起去。。 { ans++; } printf("%lld\n",ans); return 0; }
E 模拟大法好。。 先找到最近的一段,然后就可以玩了。。
#include<cstdio> #include<iostream> #include<cstring> #include<string> using namespace std; string test; int main() { int n,k; cin>>n>>k; cin>>test; int mode;//不同模式,不同标准。。 if(k==n) { mode=1; } else if(k==1) { mode=2; } else if(k>n/2) { while(k!=n) { cout<<"RIGHT"<<endl; k++; } mode=1; } else { while(k!=1) { cout<<"LEFT"<<endl; k--; } mode=2; } if(mode==1) { for(int i=n-1;i>=0;i--) { cout<<"PRINT "<<test[i]<<endl; if(i!=0) cout<<"LEFT"<<endl; } } else { for(int i=0;i<n;i++) { cout<<"PRINT "<<test[i]<<endl; if(i!=n-1) cout<<"RIGHT"<<endl; } } return 0; }
F 还是模拟,排序一下就好了。。
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; struct sb { int x; int y; }boom[100010]; int cmp(sb a,sb b) { if(abs(a.y)==abs(b.y)) return abs(a.x)<abs(b.x); return abs(a.y)<abs(b.y); } int main() { int n; scanf("%d",&n); int step=0; for(int i=1;i<=n;i++) { scanf("%d%d",&boom[i].x,&boom[i].y); if(boom[i].x) step+=2; if(boom[i].y) step+=2; step+=2; } sort(boom+1,boom+n+1,cmp); printf("%d\n",step); for(int i=1;i<=n;i++) { int mode1=0,mode2=0; if(boom[i].x>0) { printf("1 %d R\n",boom[i].x); mode1=1; } else if(boom[i].x<0) { printf("1 %d L\n",abs(boom[i].x)); mode1=2; } if(boom[i].y>0) { printf("1 %d U\n",boom[i].y); mode2=1; } else if(boom[i].y<0) { printf("1 %d D\n",abs(boom[i].y)); mode2=2; } printf("2\n"); if(mode1==1) { printf("1 %d L\n",boom[i].x); } else if(mode1==2) { printf("1 %d R\n",abs(boom[i].x)); } if(mode2==1) { printf("1 %d D\n",boom[i].y); } else if(mode2==2) { printf("1 %d U\n",abs(boom[i].y)); } printf("3\n"); } return 0; }
G题 ,这道题 又是模拟,我发现了,在cf里面即使PE 了都没问题。。
不过我还是很认真的输出了。。
这道题运气好碰巧凑对了。。
值得注意的是下界的计算,反正我因为这个wa2发之后直接偷懒了。。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<string> using namespace std; struct sb { int x; int y; char d; }node[1010]; int wa[2010][1010]; int main() { int n; cin>>n; int test; node[0].x=0; node[0].y=0; int max1=-0x3f3f3f3f; int max2=-0x3f3f3f3f; memset(wa,0,sizeof(wa)); for(int i=1;i<=n;i++) { cin>>test; node[i].x=node[i-1].x+test; if(i&1) { node[i].y=node[i-1].y+test; } else { node[i].y=node[i-1].y-test; } max1=max(max1,node[i].y); if(node[i-1].y<node[i].y) { node[i].d='s'; } else { node[i].d='x'; } } int lin=0+max1;//第零行,开始点 int k=1; int i=0; char old; while(i<=node .x) { if(node[k].x==i) { k++; if(old==1) { lin++; wa[lin][i]=2; max2=max(max2,lin);//偷懒了。。 //lin--; //i++; old=2; } else { lin--; wa[lin][i]=1; //lin++; // i++; old=1; } } else if(node[k].d=='s') { wa[lin][i]=1; max2=max(max2,lin);//偷懒了。。 lin--; i++; old=1; } else { wa[lin][i]=2; max2=max(max2,lin);//偷懒了。。 lin++; i++; old=2; } } for(int ii=1;ii<=max2;ii++) { for(int j=0;j<node .x;j++) { if(wa[ii][j]==1) printf("/"); else if(wa[ii][j]==2) printf("\\"); else printf(" "); } puts(""); } return 0; }
H Wall Painting
异或 这题不错,既然要算的是每一个组合后数的和(sum),
1。sum=第一位+第二位+第三位。。。第一位,第二位,第三位。。 他们之间是无关的。
2。这道题算的是所有东西的和,所以重复也没关系,用不到容斥,话说早上和友人讨论的32n微软面试题 应该容斥做是可行的吧。。(嘘)。。
这样就是一道简单的排列组合题目了。。
用int wa了。。 那就开 long long 吧
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const long long MOD=1000003; long long a[10010]; long long wei[64]; long long c[1010][1010]; void build() { for(long long i=0;i<=1001;i++) { c[i][0]=c[i][i]=1; for(long long j=1;j<i;j++) { c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD; } } } int main() { long long n; build(); while(scanf("%I64d",&n)!=EOF) { memset(wei,0,sizeof(wei)); long long test; long long maxlen=0; for(long long i=1;i<=n;i++) { scanf("%I64d",&test); long long cnt=0; while(test) { if(test&1) { wei[cnt]++; } test=test>>1; cnt++; } maxlen=max(maxlen,cnt); } for(long long i=1;i<=n;i++) { long long ans=0; for(long long j=0;j<maxlen;j++) { for(long long k=1;k<=min(i,wei[j]);k=k+2) { ans=(ans+(1<<j)%MOD*c[wei[j]][k]%MOD*c[n-wei[j]][i-k]%MOD)%MOD; } } printf("%I64d",ans); if(i==n) printf("\n"); else printf(" "); } } return 0; }
I Railway Tickets 这道题太有趣了,交了11次。。 因为终点可以在起点前面。。
简单的dp。。
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int a[10010]; int way[10010]; int main() { int l1,l2,l3,c1,c2,c3; int n; int s,e; scanf("%d%d%d%d%d%d",&l1,&l2,&l3,&c1,&c2,&c3); scanf("%d",&n); scanf("%d%d",&s,&e); if(s>e) swap(s,e); for(int i=2;i<=n;i++) { scanf("%d",&a[i]); } memset(way,0x3f3f3f3f,sizeof(way)); way[s]=0; for(int i=s+1;i<=e;i++) { int j=i-1; int dis=a[i]-a[j]; while(dis<=l1&&j>=s) { way[i]=min(way[i],way[j]+c1); j--; dis=a[i]-a[j]; } j=i-1; dis=a[i]-a[j]; while(dis<=l2&&j>=s) { way[i]=min(way[i],way[j]+c2); j--; dis=a[i]-a[j]; } j=i-1; dis=a[i]-a[j]; while(dis<=l3&&j>=s) { way[i]=min(way[i],way[j]+c3); j--; dis=a[i]-a[j]; } } printf("%d\n",way[e]); return 0; }
J Ministry 这道题2刷的时候居然爆内存了。。 哇擦,我第一遍做的时候怎么可以那么机智,用数字表示如何走。。用字母果断爆炸了。。
一开始想到了B题的滚动数组,因为走到下一层,上一层就没用了。
原来这就是dp里面套dp,先左扫一遍,然后右边扫一遍。。 因为某个点,到底是从左走还是从右走,一切都是趋向于最小,所以先左先右没关系。。
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int a[501]; int time[501]; int way[101][501]; int n; void print(int who,int len) { if(len==0) return ; else if(way[len][who]==1) { print(who,len-1); printf("%d",who); if(len==n) { printf("\n"); } else printf(" "); } else if(way[len][who]==2) { print(who-1,len); printf("%d ",who); } else { print(who+1,len); printf("%d ",who); } } int main() { int m; scanf("%d%d",&n,&m); memset(time,0,sizeof(time)); for(int j=1;j<=n;j++) { for(int i=1;i<=m;i++) { scanf("%d",&a[i]); } for(int i=1;i<=m;i++) { time[i]=time[i]+a[i]; way[j][i]=1; } for(int i=2;i<=m;i++) { if(time[i-1]+a[i]<time[i]) { time[i]=time[i-1]+a[i]; way[j][i]=2; } } for(int i=m-1;i>=1;i--) { if(time[i+1]+a[i]<time[i]) { time[i]=time[i+1]+a[i]; way[j][i]=3; } } } int min1=time[1]; int minwho=1; for(int i=2;i<=m;i++) { if(time[i]<min1) { min1=time[i]; minwho=i; } } print(minwho,n); return 0; }
K 题,,放一放,放一放,找规律,吃不消。。
现在可以了,根据我的手动模拟,首先来看“。。。。”这种情况,很明显2个点,然后看“。。。。。”这种情况,3个点。
于是 像这种1条的得出规律n/2+if(奇数)则1;
2*1的时候一个点 2*2 的时候1个点 2*3 的时候,我们找到规律,就是可以消去一条边 边成1*3的情况。。2*4 的情况我们可以照样消去3个点。。于是3就是关键。。这样我们就可以尽可能的去消除3 题目也就是水题了。。
#include<cstdio> #include<algorithm> using namespace std; int main() { int n,m; while(scanf("%d%d",&n,&m)==2) { if(n>m) swap(n,m); if(n==1||n==2) //2可以转化为1,1的时候没有符合要求的1*3 printf("%d\n",(m+1)/2); else//尽量用1*3消除 { n=n%3; m=m%3; if(n<m) swap(n,m);//人太懒,实在懒得分类了 if(n==2)//2可以转化为1.。 n=n/2; if(m==2) m=m/2; if(m==0&&n==0)//我就以1*3的单元来一行一行消 { printf("2\n"); } if(n==1&&m==0)//和样例差不多,旋转消。。 { printf("2\n"); } if(n==1&&m==1) { printf("1\n"); } }//最后0的全是2,其他都是1.。 卒。。 } return 0; }
L Gentlemen
身为大绅士的我,自然要华丽的做出啦。。。
感觉自己比网上题解写的好多了。。不过方法一样
用一个pre记录路径,dp来看有几条路。。并不用01背包的样子。。(反而觉得用了看不懂了)
#include<cstdio> #include<iostream> #include<cstring> using namespace std; int a[110]; int dp[1000010]; int pre[1000010]; int ans[110]; int main() { int fin; scanf("%d",&fin); int n; scanf("%d",&n); memset(dp,0,sizeof(dp)); memset(pre,-1,sizeof(pre)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } dp[0]=1; for(int i=1;i<=n;i++) { for(int j=fin;j>=a[i];j--) { if(dp[j-a[i]]) { dp[j]=dp[j]+dp[j-a[i]]; if(pre[j]==-1) pre[j]=i; } } } if(dp[fin]>1) { printf("-1\n"); } else if(dp[fin]==0) { printf("0\n"); } else { memset(ans,0,sizeof(ans)); int num=n; while(pre[fin]!=-1) { ans[pre[fin]]=1; fin=fin-a[pre[fin]]; num--; } for(int i=1;i<=n;i++) { if(!ans[i]) { num--; printf("%d",i); if(!num) { printf("\n"); } else { printf(" "); } } } } return 0; }
M Broken line 这道题一开始没读清题目意思,觉得是任何图形(奇形怪状),用数学的向量做,然后爆炸啊,写不出来啊,分类太多了。
然后,搜题解,妈呀,人家为何呢么几个等号就出来了呢?原来是方形,方形,方形,一下子水了。。。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> using namespace std; struct sb { long long x1,y1; long long x2,y2; }xian[10010]; struct sb1 { long long x; long long y; }vector1,vector2,vector3; int main() { long long n; cin>>n; for(long long i=1;i<=n;i++) { cin>>xian[i].x1>>xian[i].y1>>xian[i].x2>>xian[i].y2; } long long x,y; cin>>x>>y; long long ok=1; for(long long i=1;i<=n;i++) { if((xian[i].x1==xian[i].x2&&x==xian[i].x1&&y>=min(xian[i].y1,xian[i].y2)&&y<=max(xian[i].y2,xian[i].y1))||(xian[i].y1==xian[i].y2&&y==xian[i].y1&&x<=max(xian[i].x2,xian[i].x1)&&x>=min(xian[i].x1,xian[i].x2))) { ok=0; cout<<"BORDER"<<endl; break; } } long long cnt=0; if(ok) { for(long long i=1;i<=n;i++) { if(xian[i].x1!=xian[i].x2&&min(xian[i].x1,xian[i].x2)<x&&x<=max(xian[i].x1,xian[i].x2)&&y<xian[i].y2) { cnt++; } } if(cnt&1) { cout<<"INSIDE"<<endl; } else { cout<<"OUTSIDE"<<endl; } } return 0; }
N Beat
数据小的可怜,dfs一下就好了。。
总算最后一题了。。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int n; int flag[20]; int way[20][20]; int ans; void dfs(int who,int num,int old) { ans=max(num,ans); for(int i=0;i<n;i++) { if(!flag[i]&&way[who][i]>=old) { flag[i]=1; dfs(i,num+1,way[who][i]); flag[i]=0; } } } int main() { while(scanf("%d",&n)!=EOF) { for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { scanf("%d",&way[i][j]); } } ans=0; flag[0]=1; dfs(0,1,0); printf("%d\n",ans); } return 0; }
相关文章推荐