UVa的几道水题题解
来源:互联网 发布:知乎账号购买 编辑:程序博客网 时间:2024/05/29 19:43
And Then There Was One, Japan 2007,LA 3882 题解
Vjudge传送门
题意:
数据范围:多组数据,
题解:
显然我们已经不能模拟了,因为数据规模实在是太大啦,已经不再是猴子选大王靠模拟就可以搞出来的了。然而怎么做呢,我们可以用递推搞出来嘛?仿佛是可以的,因为如果是
代码:
#include<cstdio>#include<cstring>#include<iostream>using namespace std;int n,k,m,f[10000+1000];int main(){ while(scanf("%d%d%d",&n,&k,&m)!=EOF&&n&&k&&m){ f[1]=0; for(register int i=2;i<=n;i++)f[i]=(f[i-1]+k)%i; int ans=(m-k+1+f[n])%n; if(ans<=0) ans+=n; printf("%d\n",ans); } return 0;}
UVaLive 3905 Meteor ,Seoul 2007 题解
Vjudge传送门
题意:
给你n个点,然后这n个点会按照给出的x轴速度,y轴速度运动,我们需要求得是,现在给你一个固定的相框,输出n个点出现在这个固定的相框里最多的时候一共有n个中的多少个点
题解:
如果直接正面去求这个,会发现很难算,所以我们需要转化思路,既然是求n个点中某一时刻尽量出现更多的点在这个框里,那么我们的想法是逆向思维,先把n个点出现的时刻先计算出来,然后再记录到一个结构体里面,即一个区间l,r,表示这个点在l,r这段时间内出现次数最多,于是我们可以得出一个算法,求解在某一时刻,重叠的区间数最多,输出区间最多是多少个,显然我们可以把左端点和右端点当做两个事件,也就是说,对所有事件排了序之后我们从左至右扫描(因为时间是向量,只能线性地流逝不能纵向叠加[当然对于蛤来说除外]),如果扫到一个左端点,那么说明新进来了一个区间,如果扫到一个右端点,那么说明出去了一个区间,注意一点有点坑,也就是这道题在框上的点是不算的,因此我们需要把右端点的事件的优先级设置为比左端点大,也就是说倘若是同一个时间,一个是左端点,一个是右端点,那么右端点这个时间的优先级高于左端点,这样一来会先扫描到右端点,再扫描到左端点,也就是先出再进,才能保证答案的正确性,至此我们就已经得到了完整的算法,在计算一个点在框内的时间的时候有一个小技巧,也就是先计算x坐标位于相框区间的时间,再计算y坐标位于相框区间的时间,这样两个时间的交集显然就是x坐标位于相框区间,y坐标位于相框区间的时刻,这道题貌似没有eps的问题,但是其实可以转化成整数,貌似是同时乘以一个什么公倍数。
代码:
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;void update(int x,int a,int w,double& L,double& R){ if(a==0){ if(x<=0||x>=w) R=L-1; }else if(a>0){ L=max(L,-(double)x/a); R=min(R,(double)(w-x)/a); }else{ L=max(L,(double)(w-x)/a); R=min(R,-(double)x/a); }}const int MAXN=100000+10;struct Event{ double x;int type; bool operator < (const Event& a) const{return x<a.x||(x==a.x&&type>a.type);}}event[MAXN*2];int main(){ int T; scanf("%d",&T); while(T--){ int w,h,n,tail=0; scanf("%d%d%d",&w,&h,&n); for(register int i=1;i<=n;i++){ int x,y,a,b; scanf("%d%d%d%d",&x,&y,&a,&b); double L=0,R=1e9; update(x,a,w,L,R); update(y,b,h,L,R); if(R>L){ event[++tail]=(Event){L,0}; event[++tail]=(Event){R,1}; } } sort(event+1,event+tail+1); int cnt=0,ans=0; for(register int i=1;i<=tail;i++){ if(event[i].type==0) ans=max(ans,++cnt); else cnt--; } printf("%d\n",ans); } return 0;}
Jurassic Remains,NEERC 2003,LA 2965 题解
Vjudge传送门
题意:
大概的题意是指现在有n个由大写字母组成的字符串,选择尽量多的穿,是的每个大写字母都出现了偶数次
题解:
最开始我想的就是bitset暴力,说不定还能卡过,因为(1<=n<=24),所以我们直接bitset说不定也是可以的//直接穷举应该就可以了233.复杂度是
代码:
#include<cstdio>#include<iostream>#include<cstring>#include<map>using namespace std;map<int,int>mp;const int MAXN=100+10;int bitcount(int x){ int cnt=0; while(x){if(x&1!=0) cnt++; x>>=1;} return cnt;}int main(){ int n,A[MAXN]; char s[1000]; while(scanf("%d",&n)==1&&n){ for(register int i=0;i<=n-1;i++){ scanf("%s",s); A[i]=0; for(register int j=0;s[j]!='\0';j++) A[i]^=(1<<(s[j]-'A')); } mp.clear(); int n1=n/2,n2=n-n1; for(register int i=0;i<(1<<n1);i++){ int x=0;//表示一种集合的异或和 for(register int j=0;j<n1;j++) if(i&(1<<j)) x^=A[j]; if(!mp.count(x)||bitcount(mp[x])<bitcount(i)) mp[x]=i; } int ans=0; for(register int i=0;i<(1<<n2);i++){ int x=0; for(register int j=0;j<n2;j++) if(i&(1<<j))x^=A[n1+j]; if(mp.count(x)&&bitcount(ans)<bitcount(mp[x])+bitcount(i)) ans=(i<<n1)^mp[x]; } printf("%d\n",bitcount(ans)); for(register int i=0;i<n;i++) if(ans&(1<<i)) printf("%d ",i+1); printf("\n"); } return 0;}
Prince ans Princess,UVa 10635题解
Vjudge传送门
题意:
现在有两条长度为p+1和q+1的序列,每个序列的元素都各不相同,都是
题解:
LCS我貌似只会pq的写法,显然是要挂的(尤其是ccf老年机),所以我们想一下其他解法来解LCS,显然这道题有一个性质,也就是无论是第一条序列还是第二条序列,他们的元素都是互异的,因此我们的思路是先给A数组重新编号,从1开始,一直编到A的长度,对于B数组,如果这个位置的数在A中出现过,那么就应该是这个数在A中出现的位置的值,如果没有出现过就是0,然后我们求一下B的LIS就可以了,LIS貌似我们是可以nlogn做的,所以这道题就迎刃而解了。
其实刚才说的这个道理是很清楚的,因为我们把所有的B数组都变成了A数组中该数字出现的位置,那么如果找出一个连续递增的B数组,一定可以找到A和B的LCS为B的LIS所表示的这个LCS,也即B中找到的序列,在A中的位置要递增,显然吧如果在B中位置是递增的但是在A中位置不递增,怎么LCS?所以这道题就这么转化啦,非常愉快
代码:
#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int MAXN=250*250+10;const int INF=1000000000;int a[MAXN],b[MAXN],c[MAXN],num[MAXN],l[MAXN],g[MAXN],T,tail;int main(){ scanf("%d",&T); for(register int kase=1;kase<=T;kase++){ int N,p,q,x; scanf("%d%d%d",&N,&p,&q); memset(c,0,sizeof(c)); for(register int i=1;i<=p+1;i++) scanf("%d",&a[i]),c[a[i]]=i; for(register int i=1;i<=q+1;i++){ scanf("%d",&b[i]),b[i]=c[b[i]]; if(b[i]!=0) num[++tail]=b[i]; } int ans=0; for(register int i=1;i<=tail;i++) g[i]=INF; for(register int i=1;i<=tail;i++){ int k=lower_bound(g+1,g+tail+1,num[i])-g; l[i]=k;g[k]=num[i]; ans=max(ans,l[i]); } printf("Case %d: %d\n",kase,ans); } return 0;}/*1 3 6 71 7 5 4 8 3 91 4 3 5 6 2 8 9*/
Game of Sum,UVa 10891题解
题意:
有一个长度为n的序列,然后这个序列的元素可正可负,现在要A和B轮流取数,每次可以取左边或者右边的任意多个数,当然你可以在某一次把这个序列直接取完,A先取,求A的得分减去B的得分后的结果
题解:
显然这道题如果问的不是是A取的分减去B取的分而是A取的分加上B取的分的话,会好做得多(这不是废话嘛)…
也就是说,A和B取的分的和是一定的,就看谁取得多,谁取的少,但是总和是一定的,所以到这里我们大概已经想到了转移的方法,另一个dp[i][j]表示i到j这个区间,先手能够获得的最大收益,那么显然我们可以初始化dp数组为dp[i][i]=a[i],然后我们会发现每次转移的时候,我们可以枚举一下i和j中间的点,使得前一段先手的人拿然后留后一段给另一个人先手,或者后一段先手的人拿留前一段给另一个人先手,所以我们可以推出
然后我们每次枚举转移就可以了,但是据说还有一种可以优化到
代码:
#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int MAXN=100+10;int n,b[MAXN],a[MAXN],dp[MAXN][MAXN];//4//4 -10 -20 7 int main(){ while(scanf("%d",&n)==1&&n){ for(int i=1;i<=105;i++){ for(int j=1;j<=105;j++){ dp[i][j]=-100000000; } } b[0]=0; for(register int i=1;i<=n;i++){scanf("%d",&a[i]);dp[i][i]=a[i];b[i]=b[i-1]+a[i];} for(register int len=2;len<=n;len++){ for(register int i=1;i<=n-len+1;i++){ int j=i+len-1; for(register int k=i+1;k<=j;k++){dp[i][j]=max(dp[i][j],b[j]-b[i-1]-dp[k][j]);} dp[i][j]=max(dp[i][j],b[j]-b[i-1]); for(register int k=i;k<j;k++)dp[i][j]=max(dp[i][j],b[j]-b[i-1]-dp[i][k]); } } printf("%d\n",2*dp[1][n]-b[n]); } return 0;}
Calculator Conundrum,UVa 11549题解
题意&题解:
有一个神奇的计算器,然后每次计算之后只显示前n位,比如n为5的时候2147483647显示21474,然后我们只需要处理一下long long然后转字符串然后再转回来就行了,然后突然发现可以直接除啊…我是不是傻…竟然copy了刘汝佳的代码
代码:
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;int buf[10],T,n,k;int next(int n,int k){ if(!k) return 0; long long k2=(long long)k*k; int L=0; while(k2>0){buf[L++]=k2%10;k2/=10;} if(n>L) n=L; int ans=0; for(register int i=0;i<n;i++) ans=ans*10+buf[--L]; return ans;}int main(){ scanf("%d",&T); while(T--){ scanf("%d%d",&n,&k); int ans=k; int k1=k,k2=k; do{ k1=next(n,k1); k2=next(n,k2);if(k2>ans) ans=k2; k2=next(n,k2);if(k2>ans) ans=k2; }while(k1!=k2); printf("%d\n",ans); } return 0;}
- UVa的几道水题题解
- UVA 100题解
- UVA 401 Palindromes 题解
- APOC-UVA-0001 题解
- APOC-UVA-0002 题解
- UVa 10152 - ShellSort 题解
- APOC-UVA-0003 题解
- Uva 11732题解
- uva 1400题解
- uva live 4725题解
- uva 10534题解(lis)
- UVA细胞自动机题解
- UVA Poker Hands题解
- UVA 1632题解
- [uva 315] Network 题解
- uva 1587 题解
- uva 1339 题解
- UVa 11426题解 GCD
- HDU 4405 Aeroplane chess (概率-期望DP)【模板】
- POJ
- Elegant Construction HDU-5813 构造
- 数据结构绪论
- JS笔记(1) —— filter,includes
- UVa的几道水题题解
- 7-1 通讯录的录入与显示
- CtonOS7命令整理
- SQL实现表名更改,列名更改,约束更改
- conda
- Error:Debugging information for "project.exe" cannot be found or does not match. Binary was not ……
- #15. 3Sum
- Squid 搭建代理服务
- MATLAB中如何绘制一个球