Problem A Brain's Photos
题目大意
n行m列的矩形,每个格子有一种颜色。如果含有C、M、Y则输出#Color,否则输出#Black&White。
解题分析
= =
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define V 100008 19 #define E 2000008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 int n,m; 32 char s[10]; 33 int main(){ 34 scanf("%d%d",&n,&m); 35 int ok=1; 36 for (int i=1;i<=n;i++) 37 for (int j=1;j<=m;j++) 38 { 39 scanf("%s",s); 40 if (s[0]=='C' || s[0]=='M' || s[0]=='Y') ok=0; 41 } 42 if (ok) printf("#Black&White "); else printf("#Color "); 43 }
Problem B Bakery
题目大意
给一张n个点m条边有边权的无向图,有k个点是仓库。要求在某个非仓库点开面包店,使得其与最近的仓库的距离最小。
解题分析
枚举每个仓库点,再遍历其相邻点,统计对答案的贡献。
时间复杂度O(E)。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define V 100008 19 #define E 200008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 32 int n,m,k; 33 34 struct line{ 35 int u,v,w,nt; 36 }eg[E]; 37 int lt[V],sum=1; 38 int ok[V]; 39 void add(int u,int v,int w){ 40 eg[++sum].u=u; eg[sum].v=v; eg[sum].w=w; eg[sum].nt=lt[u]; lt[u]=sum; 41 } 42 int main(){ 43 clr(ok,0); 44 scanf("%d%d%d",&n,&m,&k); 45 rep(i,1,m){ 46 int u,v,w; 47 scanf("%d %d %d",&u,&v,&w); 48 add(u,v,w); 49 add(v,u,w); 50 } 51 rep(i,1,k){ 52 int x; 53 scanf("%d",&x); 54 ok[x]=1; 55 } 56 int ans=INF; 57 rep(u,1,n) 58 if (ok[u]){ 59 for (int i=lt[u];i;i=eg[i].nt){ 60 int v=eg[i].v; 61 if (!ok[v]) ans=min(ans,eg[i].w); 62 } 63 } 64 printf("%d ",ans==INF?-1:ans); 65 }
Problem C Pythagorean Triples
题目大意
给定一个数n,要求输出两个数m,k,使得n、m、k构成一组勾股数。
(n<=10^9,m,k<=10^10^18)
解题分析
对于1,2特判一下无解。
对于2^i的数字,等于将3,4,5这3个数扩大若干倍。
对于奇数x,可以构造出(x^2+1)/2 , (x^2-1)/2 满足条件。
对于偶数x,可以将其经过若干次除2后变成奇数,再扩大回去。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 508 19 #define M 50008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 32 LL x; 33 34 int main(){ 35 scanf("%I64d",&x); 36 int num=0; 37 while (x % 2 ==0){ 38 if (x==4) break; 39 num++; 40 x/=2; 41 } 42 if (x==4){ 43 LL y=3,z=5; 44 while (num){ 45 y*=2; 46 z*=2; 47 num--; 48 } 49 printf("%I64d %I64d ",y,z); 50 return 0; 51 } 52 LL y=(x*x+1)/2,z=y-1; 53 if (z>0){ 54 while (num){ 55 y*=2; 56 z*=2; 57 num--; 58 } 59 printf("%I64d %I64d ",z,y); 60 } 61 else printf("-1 "); 62 63 }
Problem D Persistent Bookcase
题目大意
有一个n*m的书架,每个格子可以放一本书,要求支持一下四种操作。
操作1:在a[i,j]位置上放一本书,若已经有书则不放。
操作2:将a[i,j]位置上的书移走,若没有书则不移动。
操作3:将第i行的书进行整体操作,若有书则移走,若没书则放置一本书。
操作4:回到之前某个操作的状态。
解题分析
虽然题意中强调了这是一种可持久化的数据结构,但一般来说这种题不会考虑用可持久化来解决= =
由于有操作4,数据又没有强制在线,一个自然的想法就是离线处理。
按照询问的顺序,可以建成一棵询问树,每次递归回溯解决即可。
对于维护操作3,可以打标记处理,也可以直接开n个bitset,每次用自带的函数flip暴力修改。
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <bitset> 8 #include <string> 9 #include <vector> 10 #include <cstdio> 11 #include <cstdlib> 12 #include <cstring> 13 #include <cassert> 14 #include <iostream> 15 #include <algorithm> 16 #pragma comment(linker,"/STACK:102400000,102400000") 17 using namespace std; 18 19 #define N 100008 20 #define M 200008 21 #define LL long long 22 #define lson l,m,rt<<1 23 #define rson m+1,r,rt<<1|1 24 #define clr(x,v) memset(x,v,sizeof(x)); 25 #define bitcnt(x) __builtin_popcount(x) 26 #define rep(x,y,z) for (int x=y;x<=z;x++) 27 #define repd(x,y,z) for (int x=y;x>=z;x--) 28 const int mo = 1000000007; 29 const int inf = 0x3f3f3f3f; 30 const int INF = 2000000000; 31 /**************************************************************************/ 32 33 bitset <1008> a[1008]; 34 int ans[M]; 35 int f[N]; 36 int n,m,k; 37 struct node{ 38 int type,x,y; 39 }q[M]; 40 struct line{ 41 int u,v,nt; 42 }eg[M]; 43 int lt[N],sum=1; 44 void add(int u,int v){ 45 eg[++sum].u=u; eg[sum].v=v; eg[sum].nt=lt[u]; lt[u]=sum; f[v]=u; 46 } 47 void dfs(int u){ 48 //printf("%d %d %d %d ",u,q[u].type,f[u],ans[f[u]] ); 49 int p; 50 if (q[u].type==4){ 51 ans[u]=ans[f[u]]; 52 } 53 if (q[u].type==1){ 54 p = a[q[u].x][q[u].y]; 55 a[q[u].x][q[u].y]=1; 56 if (p==1) ans[u]=ans[f[u]]; else ans[u]=ans[f[u]]+1; 57 } 58 if (q[u].type==2){ 59 p = a[q[u].x][q[u].y]; 60 a[q[u].x][q[u].y]=0; 61 if (p==1) ans[u]=ans[f[u]]-1; else ans[u]=ans[f[u]]; 62 } 63 if (q[u].type==3){ 64 int one=a[q[u].x].count(); 65 a[q[u].x].flip(); 66 if (a[q[u].x][0]==0) one=one-(1008-m); 67 ans[u]=ans[f[u]]-one+m-one; 68 } 69 for (int i=lt[u];i;i=eg[i].nt) 70 dfs(eg[i].v); 71 if (q[u].type==1||q[u].type==2){ 72 a[q[u].x][q[u].y]=p; 73 } 74 if (q[u].type==3){ 75 a[q[u].x].flip(); 76 } 77 78 } 79 80 int main(){ 81 scanf("%d %d %d",&n,&m,&k); 82 rep(i,1,k){ 83 int x,y,z; 84 scanf("%d%d",&x,&y); 85 if (x==1||x==2) scanf("%d",&z); 86 q[i].type=x; 87 q[i].x=y; 88 q[i].y=z; 89 if (q[i].type==4){ 90 add(q[i].x,i); 91 } 92 else add(i-1,i); 93 } 94 dfs(0); 95 //a[1][0]=1; 96 //a[1][1]=1; 97 //a[1].flip(); 98 rep(i,1,k) printf("%d ",ans[i] ); 99 }
题目大意
给一个n*m的矩阵,每个点有点权。上面有k条链,每条链长度为len,链上的点有点权。
保证所有链不会相交。每条链有个开关,若关闭则不计算链上的点权。要求支持两种操作。
操作1:询问某个子矩阵的权值和。操作2:开关某条链。
n,m,k,操作1总数<=2000, 操作总数<=1000000
解题分析
由于操作1的数量较少,考虑离线处理询问。
用二维树状数组计算每条链对每个询问的贡献。
时间复杂度 (n^2logn^2)
也可以用前缀和进行维护,将询问按照x坐标排序后,用一维树状数组维护前缀和。
时间复杂度 (n^2logn)
参考程序
1 #include <map> 2 #include <set> 3 #include <stack> 4 #include <queue> 5 #include <cmath> 6 #include <ctime> 7 #include <string> 8 #include <vector> 9 #include <cstdio> 10 #include <cstdlib> 11 #include <cstring> 12 #include <cassert> 13 #include <iostream> 14 #include <algorithm> 15 #pragma comment(linker,"/STACK:102400000,102400000") 16 using namespace std; 17 18 #define N 2008 19 #define M 50008 20 #define LL long long 21 #define lson l,m,rt<<1 22 #define rson m+1,r,rt<<1|1 23 #define clr(x,v) memset(x,v,sizeof(x)); 24 #define bitcnt(x) __builtin_popcount(x) 25 #define rep(x,y,z) for (int x=y;x<=z;x++) 26 #define repd(x,y,z) for (int x=y;x>=z;x--) 27 const int mo = 1000000007; 28 const int inf = 0x3f3f3f3f; 29 const int INF = 2000000000; 30 /**************************************************************************/ 31 int n,m,k,qcnt,wcnt; 32 int len[N],flag[N],x[N][N],y[N][N],z[N][N]; 33 char s[10]; 34 LL ans[N][N]; 35 struct que{ 36 int type,a,b,c,d; 37 }q[2000008],w[N]; 38 struct Binaty_Indexed_Tree{ 39 LL a[N][N]; 40 void clear(){ 41 clr(a,0); 42 } 43 void insert(int x,int y,int val){ 44 for (int i=x;i<N;i+=i & (-i)) 45 for (int j=y;j<N;j+=j & (-j)) 46 a[i][j]+=val; 47 } 48 LL sigma(int x,int y){ 49 if (x==0||y==0) return 0; 50 LL res=0; 51 for (int i=x;i>0;i-=i & (-i)) 52 for (int j=y;j>0;j-=j & (-j)) 53 res+=a[i][j]; 54 return res; 55 } 56 LL query(int x1,int y1,int x2,int y2){ 57 LL res=0; 58 res = sigma(x2,y2)-sigma(x1-1,y2)-sigma(x2,y1-1)+sigma(x1-1,y1-1); 59 return res; 60 } 61 }T; 62 int main(){ 63 scanf("%d%d%d",&n,&m,&k); 64 rep(i,1,k){ 65 scanf("%d",&len[i]); 66 rep(j,1,len[i]) scanf("%d%d%d",&x[i][j],&y[i][j],&z[i][j]); 67 } 68 scanf("%d",&qcnt); wcnt=0; 69 rep(i,1,qcnt){ 70 scanf("%s",s); 71 if (s[0]=='A'){ 72 q[i].type=1; 73 scanf("%d%d%d%d",&q[i].a,&q[i].b,&q[i].c,&q[i].d); 74 w[++wcnt]=q[i]; 75 } 76 if (s[0]=='S'){ 77 q[i].type=2; 78 scanf("%d",&q[i].a); 79 } 80 } 81 T.clear(); 82 rep(i,1,k){ 83 rep(j,1,len[i]) T.insert(x[i][j],y[i][j],z[i][j]); 84 rep(j,1,wcnt) ans[j][i]=T.query(w[j].a,w[j].b,w[j].c,w[j].d); 85 rep(j,1,len[i]) T.insert(x[i][j],y[i][j],-z[i][j]); 86 } 87 int id=0; 88 rep(j,1,k) flag[j]=1; 89 rep(i,1,qcnt){ 90 if (q[i].type==2) flag[q[i].a]^=1; 91 if (q[i].type==1){ 92 LL res=0; id++; 93 rep(j,1,k) if (flag[j]) res+=ans[id][j]; 94 printf("%I64d ",res); 95 } 96 } 97 }