HDU 5277 YJC counts stars
飞机票:http://acm.hdu.edu.cn/showproblem.php?pid=5277
题意:就是给你n个点n个坐标xi,yi(1<=i<=n),然后给你m条边,表示u和v相连,保证没重边,也保证没有边相交。然后 让你求最大的点子集,使里面的点可以两两相连(不是图相连,线段相连),且求处个数。
分析:其实分析分析,就发现最大就只有4个点的点急,因为5个点就会有边相交,与题目不符,所以只要枚举到4个点就行了,具体怎么枚举才比较好?可以先枚举两两的,就是加入i和j有边相连,就把i和j算一对保存起来,这样我们就知道两两相连的子集个数有多少个了,怎么枚举三个的,很简单,只要把两个相连的与一个个点比较,只要这两个点能同事与第三个点连接,那么就是ok的,这里注意:假设i和j和k是属于三个相连的,我们求出来两两的就是(i,j)(i,k)(j,k)然后枚举三个点的时候会有三种方法,但是实际上就只有1种,所以答案要/3,这样我们就知道三个点的自己个数了,现在是四个点了,四个点也很方便,只要把两个点的两两进行判断就行了,只要互不相同然后互相连接就可以了,但是要注意:假设我们i,j,p,q,是四个相连的点集,那么我们两两求出来的就是(i,j)(i,p)(i,q)(j,p)(j,q)(p,q),这样的话,他们两两按数序的话会求出来三组,因为我们重复计算了,所以答案要/3到此为止,所有的都已经判断了, 按照4,3,2,1只要有一个是满足的,直接ok,结束。然后啪啪啪就可以AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=1234; int x[maxn],y[maxn]; int ai[maxn][maxn]; int n,m; void init() { for(int i=1; i<=n; i++)scanf("%d%d",&x[i],&y[i]); int u,v; memset(ai,0,sizeof(ai)); for(int i=1; i<=m; i++) { scanf("%d%d",&u,&v); ai[u][v]=ai[v][u]=1; } } int bi[maxn*maxn][2]; void play() { if(m==0) { printf("1 %d\n",n); return; } if(m==1) { printf("2 1\n"); return ; } int st=1; int sum2=0; //判断连通性 for(int i=1; i<=n; i++) { for(int j=i+1; j<=n; j++) { if(ai[i][j]) { bi[st][0]=i; bi[st][1]=j; st++; sum2++; } } } int sum3=0; //判断三个点的 for(int i=1; i<st; i++) { for(int j=1; j<=n; j++) { int u=bi[i][0]; int v=bi[i][1]; if(ai[u][j]&&ai[v][j]) { sum3++; } } } int sum4=0; //判断四个点的 for(int i=1; i<st; i++) { for(int j=i+1; j<st; j++) { int u1=bi[i][0]; int u2=bi[i][1]; int v1=bi[j][0]; int v2=bi[j][1]; if(u1!=v1&&u1!=v2&&u2!=v1&&u2!=v2&&ai[u1][v1]&&ai[u1][v2]&&ai[u2][v1]&&ai[u2][v2])sum4++; } } if(sum4!=0) { printf("4 %d\n",sum4/3); } else if(sum3!=0) { printf("3 %d\n",sum3/3); } else if(sum2!=0) { printf("2 %d\n",sum2); } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
HDU 5276 YJC tricks time
飞机票:http://acm.hdu.edu.cn/showproblem.php?pid=5276
题意:就是给你时钟的分针和时针的角度,且乘上12000,求现在的时间是几时几分几秒,且秒要是10的倍数。而且题目给的是劣角的角度,即不会大于12000*180,
分析:枚举时间的话肯定不会超时,怎么判断角度呢,我们可以先求出分针的角度,加入当前的时间是i:j:k,且k是10的倍数,那么分针的角度就是j*6+0.1*k,因为一秒分钟转0.1度,分针一分钟转6度,可以知道j*6+0.1*k是整数,假设是q。我们知道时针转的角度是i*30,因为小时转30度,且每分钟转1/360*30,所以总的转了i*30+30*q/360,因为有精度误差,因为30*q不一定能整除,但是题目给了乘上12000,所以可以直接提高倍数,就是q=12000*q,设时针角度为p,所以p=i*30*12000+30*q/360,因为q已经乘过了,所以不用乘了。这样就可以保证q和p都是整数,但是还有个问题就是劣角,所以一共有两个角。一个是abs(q-p),一个是360*12000-abs(q-p),因为扩大了12000,只要其中一个和输入的角度一样就是对的时间。中间不要用double,直接int,因为我double就wa,int就AC,然后啪啪啪就可以AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #include <stack> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; int n; void init() { } void play() { for(int i=0; i<=11; i++) { for(int j=0; j<=59; j++) { for(int k=0; k<=59; k+=10) { int q=j*6; q+=0.1*k; q*=12000; int p=i*30*12000; p+=q*30/360; int s1=abs(q-p); int s2=360*12000-s1; if(s1==n||s2==n) { printf("%02d:%02d:%02d\n",i,j,k); } } } } } int main() { while(scanf("%d",&n)!=EOF) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
HDU 5273 Dylans loves sequence
飞机票:http://acm.hdu.edu.cn/showproblem.php?pid=5273
题意:给你N个数ai 1<=i<=n,N<=1000,以及Q个查询,Q<=100000,每个查询有两个整数L,R 求[L,R]逆序对的数量(逆序对就是当i<j 时,ai>aj)
分析:要求[L,R]之间的逆序对数量,且Q<=100000,我们可以O(n^2)的时间求出[i,j]之间的逆序对的数量,i<=j,然后用O(1)的时间查询答案,具体怎么算,我们先来个辅助数组fi[maxn][maxn],其中maxn是题目给的最大N,因为N最大是1000,所以数组大小为1000000,不会爆空间,然后我们令fi[i][j],表示以i为逆序对的端点,然后计算j从i~1,以j为右端点的总数,用递推就可以在O(n^2)算出来,接着来个sum[maxn][maxn]数组,这个数组就是答案,其中sum[i][j]表示从i到j一共用多少组逆序对,因为我们有fi数组,所以只要累加fi数组就可以了,j从i到n,然后sum[i][j]=sum[i][j-1]+fi[j][i];这个怎么解释,好好想想就知道了,假设我们要知道从i到j的sum,因为我们已经知道sum[i][j-1]的sum了,而以j结尾,且已i开始的之间的总数就是fi[j][i],所以加上就是答案,复杂度O(n*n+Q),然后啪啪啪,就可以AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <map> #include <stack> #include <vector> #include <queue> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=1234; LL ai[maxn]; LL fi[maxn][maxn]; LL sum[maxn][maxn]; int n,Q; void init() { for(int i=1; i<=n; i++)scanf("%I64d",&ai[i]); } void play() { memset(fi,0,sizeof(fi)); memset(sum,0,sizeof(sum)); for(int i=1; i<=n; i++) { fi[i][i]=0; for(int j=i-1; j>=1; j--) { fi[i][j]=fi[i][j+1]; if(ai[i]<ai[j]) { fi[i][j]++; } } } for(int i=1;i<=n;i++){ sum[i][i]=0; for(int j=i+1;j<=n;j++){ sum[i][j]=sum[i][j-1]+fi[j][i]; } } int L,R; while(Q--) { scanf("%d%d",&L,&R); printf("%I64d\n",sum[L][R]); } } int main() { while(scanf("%d%d",&n,&Q)!=EOF) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
HDU 5269 ZYB loves Xor I
飞机票:http://acm.hdu.edu.cn/showproblem.php?pid=5269
题意:给你一个数组A,A[i]^A[j]之后,假设为P,求lowbit(P)(就是P最低位为1的位置,然后就是2^为1位置)。然后求和,这里的话要计算两遍,即i和j j和i算两个,并不算一个。
分析:起先以为是最低位:不用为2的幂掌握的不够深刻啊。然后百度才知道要幂的。。。这次印象深刻了这种题的话,可以用分治,即分成两个块然后求值。具体怎么求值:
(1)先把所有的数转换为2进制。
(2)从最低位开始,如果是1就放入左边块,如果是0就放入右边块。(这里我是定义vector l,r ,每次是1就存入l,右边就存入r),这样的话就知道l里的元素和r里的元素是异或之后最低位为当前深度的2的幂,然后把l的大小*r的大小*2加到答案里去。*2是因为l和r算一边,然后r和l算遍。
(3)然后把l和r分别进行第二步。因为l和r已经不相干了。这里要及时退出,就是当l和r其中是0时就要退出,不然会TLE
总体复杂的O(n*logn),然后啪啪啪,就可以AC了
/* Author:Chieh Because Of Coding */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <map> #include <stack> #include <vector> #include <queue> #define LL long long #define INF 1e9 #define EPS 1e-9 using namespace std; const int maxn=5*12345; int T; int n; int ai[maxn]; int bi[30]; struct he { bool isok[30]; } Sky[maxn]; int MOD=998244353; void getBir() { for(int i=1; i<=n; i++) { memset(Sky[i].isok,0,sizeof(Sky[i].isok)); for(int j=29; j>=0; j--) { if(ai[i]-bi[j]>=0) { ai[i]-=bi[j]; Sky[i].isok[j]=1; } } } } void init() { scanf("%d",&n); for(int i=1; i<=n; i++)scanf("%d",&ai[i]); getBir(); } LL ans; void DFS(vector<int> V,int depth) { if(depth==30) { return; } if(V.size()==0)return; vector<int> l; vector<int> r; for(int i=0; i<V.size(); i++) { int id=V[i]; if(Sky[id].isok[depth]) { l.push_back(id); } else { r.push_back(id); } } int ls=l.size(); int rs=r.size(); LL p=ls*rs; ans=(ans+((p*(bi[depth]%MOD)%MOD)*2)%MOD)%MOD; DFS(l,depth+1); DFS(r,depth+1); } int Case; void play() { ans=0; vector<int> V; for(int i=1;i<=n;i++)V.push_back(i); DFS(V,0); printf("Case #%d: %I64d\n",++Case,ans); } int main() { bi[0]=1; for(int i=1; i<=29; i++){bi[i]=bi[i-1]*2;} scanf("%d",&T); Case=0; while(T--) { init(); play(); } // cout << "Hello world!" << endl; return 0; }
HDU 5154 Harry and Magical Computer
飞机票: http://acm.hdu.edu.cn/showproblem.php?pid=5154
很好理解的题。。。
题目分析:最多100个点 跑一边floyd 看是否有环 复杂度 0(n^3)。一个trick就是自己到自己有环也是NO
/* Author:Chieh Grow up happy */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <map> #include <queue> #include <stack> #include <vector> #define LL long long using namespace std; const int maxn=123; int ai[maxn][maxn]; int n,m; void init() { int u,v; memset(ai,0,sizeof(ai)); for(int i=1; i<=m; i++) { scanf("%d%d",&u,&v); ai[u][v]=1; } } void play() { for(int k=1; k<=n; k++) { for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(ai[i][k]&&ai[k][j]) { ai[i][j]=1; } } } } for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { if(ai[i][j]&&ai[j][i]) { printf("NO\n"); return; } } } printf("YES\n"); } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); play(); } return 0; }
HDU 5150 Sum Sum Sum
链接 http://acm.hdu.edu.cn/showproblem.php?pid=5150
Bestcoder的一道题。。。直接暴力即可。。。但是看见被hack的好多。。。原来是在1这里出了问题。。。后面几个题没几个做的出来。看来这场的题偏难了
/* Author:Chieh Grow up happy */ #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <queue> #include <map> #include <stack> #include <vector> #define LL long long using namespace std; const int maxn=1234; int n; int ai[maxn]; int bi[maxn]; void init() { for(int i=1; i<=n; i++)scanf("%d",&bi[i]); } void play() { int over=0; for(int i=1; i<=n; i++) { if(!ai[bi[i]])over+=bi[i]; } printf("%d\n",over); } int main() { memset(ai,0,sizeof(ai)); for(int i=1; i<=1000; i++) { for(int j=2; j<i; j++) { if(i%j==0)ai[i]=1; } } while(scanf("%d",&n)!=EOF) { init(); play(); } return 0; }