4.4
http://codeforces.com/gym/100623/attachments
A题
题意:有n个球(0~n-1)先放在A个盒子(0~A-1)里面,然后将(0~n-1)放在B个盒子(0~B-1),问abs(A盒子所在位置-B盒子所在位置)的和是多少?
思路:现将小球分成两部分(1.k个A与B的公倍数,2.n%(A与B的公倍数)),对于每部分进行模拟解决。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 using namespace std; 7 long long gcd(long long a,long long b) 8 { 9 if(b==0) return a; 10 return gcd(b,a%b); 11 } 12 long long solve(long long n,long long a,long long b) 13 { 14 long long now=0,x=0,y=0,tmp=0,ans=0; 15 while(now<n) 16 { 17 tmp=min(a-x,b-y); 18 if(tmp+now>n) tmp=n-now; 19 ans=ans+tmp*abs(x-y); 20 x=(x+tmp)%a; 21 y=(y+tmp)%b; 22 now=now+tmp; 23 } 24 return ans; 25 } 26 int main() 27 { 28 long long t; 29 scanf("%lld",&t); 30 { 31 long long n,A,B; 32 while(t--) 33 { 34 scanf("%lld%lld%lld",&n,&A,&B); 35 if(A==B) 36 { 37 printf("0\n"); 38 continue; 39 } 40 long long k=A*B/gcd(A,B); 41 long long ans=0; 42 if(k>n) ans=solve(n,A,B); 43 else ans=n/k*solve(k,A,B)+solve(n%k,A,B); 44 printf("%lld\n",ans); 45 } 46 } 47 return 0; 48 }
B题
C题
D题
题意:给你n个花盆,然后给你m次操作(1.从p花盆开始将num个花插入花盆,2.询问从 l 到 r 的花盆中有多少朵花),对于操作1打印插入花的起始花盆和结束花盆,对于操作2打印 l 到 r 之间的花朵数量。
思路:可以和容易看出是一道线段树操作的题目,不过在使用线段树的时候要进行二分查找插入花朵的起始位置和结束位置。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 using namespace std; 8 const int maxn=51000; 9 struct node 10 { 11 int l,r,m,lazy; 12 } a[maxn<<2]; 13 void build(int l,int r,int k) 14 { 15 a[k].l=l,a[k].r=r,a[k].m=0,a[k].lazy=-1; 16 if(l==r) 17 return ; 18 int mid=(l+r)/2; 19 build(l,mid,k*2); 20 build(mid+1,r,k*2+1); 21 } 22 void push_up(int k) 23 { 24 if(a[k].lazy==-1) 25 return ; 26 if(a[k].lazy==1) 27 { 28 a[k].lazy=-1; 29 a[k*2].lazy=a[k*2+1].lazy=1; 30 a[k*2].m=a[k*2].r-a[k*2].l+1; 31 a[k*2+1].m=a[k*2+1].r-a[k*2+1].l+1; 32 } 33 if(a[k].lazy==0) 34 { 35 a[k].lazy=-1; 36 a[k*2].m=a[k*2+1].m=0; 37 a[k*2].lazy=a[k*2+1].lazy=0; 38 } 39 } 40 void push_down(int k) 41 { 42 a[k].m=a[k*2].m+a[k*2+1].m; 43 } 44 void ins(int l,int r,int k,int d) 45 { 46 if(l<=a[k].l&&a[k].r<=r) 47 { 48 a[k].lazy=d; 49 a[k].m=(a[k].r-a[k].l+1)*d; 50 return ; 51 } 52 push_up(k); 53 if(r<=a[k*2].r) ins(l,r,k*2,d); 54 else if(l>=a[k*2+1].l) ins(l,r,k*2+1,d); 55 else 56 { 57 ins(l,r,k*2,d); 58 ins(l,r,k*2+1,d); 59 } 60 push_down(k); 61 return ; 62 } 63 int query(int l,int r,int k) 64 { 65 if(l<=a[k].l&&a[k].r<=r) 66 { 67 return a[k].m; 68 } 69 push_up(k); 70 int ans=0; 71 if(r<=a[k*2].r) ans+=query(l,r,k*2); 72 else if(l>=a[k*2+1].l) ans+=query(l,r,k*2+1); 73 else 74 { 75 ans+=query(l,r,k*2); 76 ans+=query(l,r,k*2+1); 77 } 78 return ans; 79 } 80 int main() 81 { 82 int n,m,t,x,y,z; 83 while(~scanf("%d",&t)) 84 { 85 while(t--) 86 { 87 scanf("%d%d",&n,&m); 88 build(0,n-1,1); 89 while(m--) 90 { 91 scanf("%d%d%d",&x,&y,&z); 92 if(x==1) 93 { 94 int tmp=(n-y)-query(y,n-1,1); 95 if(tmp==0) 96 { 97 printf("Can not put any one.\n"); 98 continue; 99 } 100 if(tmp>z) 101 tmp=z; 102 int rr=n-1,ll=y,mid; 103 int l,r; 104 while(ll<=rr) 105 { 106 mid=(ll+rr)/2; 107 if(mid-y+1-query(y,mid,1)>0) 108 { 109 l=mid; 110 rr=mid-1; 111 } 112 else 113 ll=mid+1; 114 } 115 ll=y,rr=n-1; 116 while(ll<=rr) 117 { 118 mid=(ll+rr)/2; 119 if(mid-y+1-query(y,mid,1)>=tmp) 120 { 121 r=mid; 122 rr=mid-1; 123 } 124 else 125 ll=mid+1; 126 } 127 printf("%d %d\n",l,r); 128 ins(l,r,1,1); 129 } 130 else 131 { 132 int cnt=query(y,z,1); 133 printf("%d\n",cnt); 134 ins(y,z,1,0); 135 } 136 } 137 printf("\n"); 138 } 139 } 140 return 0; 141 }
E题
F题
G题
H题
题意:给你n行m列的矩阵,当 t 阶方阵中行和列都是对称的时候最大的 t 是多少。
思路:分别求行和列的回文数,然后分别计算行和列的回文数的最小值k,然后求k的最大值
1 #include <iostream> 2 #include<cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 using namespace std; 7 const int inf=0x3f3f3f3f; 8 const int maxn=1005; 9 int a[maxn][maxn],num1[maxn][maxn],num2[maxn][maxn]; 10 int main() 11 { 12 int n,m,t; 13 while(~scanf("%d",&t)) 14 { 15 while(t--) 16 { 17 scanf("%d%d",&n,&m); 18 n=n*2+1; 19 m=m*2+1; 20 for(int i=1;i<=n;i++) 21 { 22 for(int j=1;j<=m;j++) 23 { 24 if(i&1||j&1) 25 a[i][j]=-1; 26 else 27 { 28 scanf("%d",&a[i][j]); 29 } 30 } 31 } 32 int l=0; 33 for(int i=1;i<=n;i++) 34 { 35 for(int j=1;j<=m;j++) 36 { 37 l=0; 38 for(int k=0;j-k>=1&&j+k<=m;k++) 39 { 40 if(a[i][j-k]==a[i][j+k]) 41 l=k; 42 else 43 break; 44 } 45 num1[i][j]=l; 46 } 47 } 48 for(int i=1;i<=n;i++) 49 { 50 for(int j=1;j<=m;j++) 51 { 52 l=0; 53 for(int k=0;i-k>=1&&i+k<=n;k++) 54 { 55 if(a[i-k][j]==a[i+k][j]) 56 l=k; 57 else 58 break; 59 } 60 num2[i][j]=l; 61 } 62 } 63 int minn,maxx; 64 int ans=0; 65 for(int i=1;i<=n;i++) 66 { 67 for(int j=1;j<=m;j++) 68 { 69 minn=inf,maxx=inf; 70 for(int k=0;i-k>=1&&i+k<=n&&j-k>=1&&j+k<=m;k++) 71 { 72 minn=min(minn,min(num1[i-k][j],num1[i+k][j])); 73 maxx=min(maxx,min(num2[i][j-k],num2[i][j+k])); 74 if(minn<k||maxx<k) 75 break; 76 ans=max(ans,k); 77 } 78 } 79 } 80 printf("%d\n",ans); 81 } 82 } 83 return 0; 84 }
I题
题意:先输入n和m,然后输入n个点 xi 和 yi 意味着在有一条横向的(xi,yi~xi+1,yi)线段,然后输入m条纵向的线段(xi,yi~~xi,yi+1),问有多少条线段能够独立存在(与其他的线段都不会相连)
思路:先输入n条横向线段,然后找出与m条纵向线段相连的横向线段,然后利用深搜的思想找出和纵向线段相连的而没有和其他纵向线段相连的线段数量。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 using namespace std; 8 const int maxn=10005; 9 vector<int>vec[maxn]; 10 int x[maxn],y[maxn],flag[maxn],n,m,cnt[maxn]; 11 int solve(int k) 12 { 13 for(int i=0;i<vec[k].size();i++) 14 { 15 int u=vec[k][i]; 16 if(!cnt[u]) 17 { 18 cnt[u]=1; 19 if(!flag[u]||solve(flag[u])) 20 { 21 flag[u]=k; 22 return 1; 23 } 24 } 25 } 26 return 0; 27 } 28 int KM() 29 { 30 int ret=0; 31 memset(flag,0,sizeof(flag)); 32 for(int i=1;i<=m;i++) 33 { 34 memset(cnt,0,sizeof(cnt)); 35 if(solve(i)) 36 ret++; 37 } 38 return ret; 39 } 40 int main() 41 { 42 int a,b; 43 while(~scanf("%d%d",&n,&m)) 44 { 45 if(n==0&&m==0) 46 { 47 break; 48 } 49 for(int i=1; i<=n; i++) 50 scanf("%d%d",&x[i],&y[i]); 51 for(int j=1; j<=m; j++) 52 { 53 scanf("%d%d",&a,&b); 54 vec[j].clear(); 55 for(int i=1; i<=n; i++) 56 if((x[i]==a||x[i]+1==a)&&(b==y[i]||b+1==y[i])) 57 vec[j].push_back(i); 58 } 59 printf("%d\n",n+m-KM()); 60 } 61 return 0; 62 }
J题