解题思路:
先将题目给定的“黑带”一条条画到图上去,此时可以通过广搜(深搜会爆)得到“联通块”的个数为n,然后我们反过来将“黑带”一条条消除。先消除一个“黑块”,若黑块附近没有任何白块,此时“联通块”的个数加一,即n+1,若黑块附近存在白块,记录不同“白色联通块”的种数s,此时“联通块个数”为n-s+1,最后合并这些“白色联通块”。若我们通过标数字的方法来表示“联通块”,那么对“联通块”合并时肯定会超时(最差0(n)),所以我们使用并查集来合并这些“联通块”(0(lgn))。
代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> #include <set> using namespace std; const int N = 1010; const int M = 10010; int graph[N][N],parent[N*N],vec[M]; struct Node{ int x1,y1,x2,y2; }node[M]; int n,m,q; int dx[] = {0,0,1,-1}; int dy[] = {1,-1,0,0}; void init() { memset(graph,0,sizeof(graph)); for(int i = 0; i < N*N; ++i) parent[i] = i; } bool inside(int x,int y) { return x >= 1 && x <= n && y >= 1 && y <= m; } int id(int x,int y) { return (x-1)*m+y; } int find(int x) { while(x != parent[x]){ parent[x] = parent[parent[x]]; x = parent[x]; } return x; } void merge(int x,int y) { int i = find(x); int j = find(y); if(i != j) parent[i] = j; } int solve(int x,int y,int ans) { graph[x][y]--; int flag = 0; set<int>st; if(graph[x][y] == 0){ for(int i = 0; i < 4; ++i){ int nx = x+dx[i]; int ny = y+dy[i]; if(inside(nx,ny) && graph[nx][ny] == 0){ merge(id(x,y),id(nx,ny)); flag = 1; st.insert(find(id(nx,ny))); } } if(flag) ans = ans-st.size()+1; else ans++; } return ans; } int main() { // freopen("D:\\12.in","r",stdin); // freopen("D:\\out.txt","w",stdout); while(~scanf("%d%d%d",&n,&m,&q)){ init(); for(int i = 1; i <= q; ++i){ scanf("%d%d%d%d",&node[i].x1,&node[i].y1,&node[i].x2,&node[i].y2); for(int j = node[i].x1; j <= node[i].x2; ++j) for(int k = node[i].y1; k <= node[i].y2; ++k) graph[j][k]++; } for(int i = 1; i <= n; ++i){ for(int j = 1; j <= m; ++j){ if(!graph[i][j] && inside(i,j+1) && !graph[i][j+1]) merge(id(i,j),id(i,j+1)); if(!graph[i][j] && inside(i+1,j) && !graph[i+1][j]) merge(id(i,j),id(i+1,j)); } } int ans = 0; for(int i = 1; i <=n ; ++i){ for(int j = 1; j <= m; ++j){ if(!graph[i][j] && id(i,j) == find(id(i,j))) ans++; } } vec[q] = ans; for(int i = q; i > 1; --i){ for(int j = node[i].x1; j <= node[i].x2; ++j){ for(int k = node[i].y1; k <= node[i].y2; ++k){ ans = solve(j,k,ans); } } vec[i-1] = ans; } for(int i = 1; i <= q; ++i) printf("%d\n",vec[i]); } return 0; } /********************************************************************** Problem: 2022 User: zhiyuanjiang Language: C++ Result: AC Time:432 ms Memory:10192 kb **********************************************************************/
解题思路:
贪心,在股价最低点买入,最高点卖出,最多能操作的股票数目为100000
代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> using namespace std; typedef long long llt; const int N = 400; llt data[N]; int main() { int n; while(~scanf("%d",&n)){ for(int i = 1; i <= n; ++i) scanf("%lld",&data[i]); llt money = 100,stnum = 0,price = 600; int i = 1; while(i <= n){ while(i <= n && price >= data[i]){ price = data[i]; i++; } stnum = money/data[--i]; if(stnum > 100000) stnum = 100000; money -= stnum*data[i]; price = data[i]; while(i <= n && price <= data[i]){ price = data[i]; i++; } money += stnum*data[--i]; stnum = 0; price = data[i]; i++; } money += stnum*price; printf("%lld\n",money); } return 0; } /********************************************************************** Problem: 2026 User: zhiyuanjiang Language: C++ Result: AC Time:4 ms Memory:2024 kb **********************************************************************/
指数循环节,第一次写这种题,一直弄不懂为啥有时不满足那个判断条件的情况下也能用这玩意,数学好难
扫描二维码关注公众号,回复:
1024052 查看本文章
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> #include <set> using namespace std; typedef long long llt; const int N = 1010; const int M = 10010; llt phi(llt n) { llt ans = n; for(int i = 2; i*i <= n; ++i){ if(n%i == 0) ans = ans-ans/i; while(n%i == 0) n /= i; } if(n > 1) ans = ans-ans/n; return ans; } llt fast_mi(llt x,llt n,llt mod) { llt ans = 1; while(n){ if(n&1) ans = ans*x%mod; n >>= 1; x = x*x%mod; } return ans; } llt expoinal(llt x,llt mod) { if(mod == 1) return 0; if(x == 1) return 1%mod; if(x == 2) return 2%mod; if(x == 3) return 9%mod; if(x == 4) return fast_mi(4,9,mod); llt r = phi(mod); llt ans = expoinal(x-1,r)+r; ans = fast_mi(x,ans,mod); return ans; } int main() { // freopen("D:\\in1.in","r",stdin); // freopen("D:\\out.txt","w",stdout); llt n,m; while(~scanf("%lld%lld",&n,&m)){ printf("%lld\n",expoinal(n,m)); } return 0; } /********************************************************************** Problem: 2021 User: zhiyuanjiang Language: C++ Result: AC Time:4 ms Memory:2024 kb **********************************************************************/
解题思路:官方题解如下
只要求出上面“1式”大于1的临界条件即可,x = n/(p-1)
数学菜呀,这里看了好久才看明白。
代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> using namespace std; typedef long long llt; const int N = 10010; const double esp = 1e-6; //lgamma(n):求ln((n-1)!); //tgamma(n):求(n-1)! int main() { int n,p; while(~scanf("%d%d",&n,&p)){ double x = n/(p-1); double ans = x*p; ans *= exp(lgamma(n+1)+lgamma(n+x-p+1)-lgamma(n-p+2)-lgamma(n+x+1)); printf("%.9f\n",ans); } return 0; }
模拟题,完善一个等级系统,在25级到6级时,赢得一场获得一颗星,若连续赢三场以上,额外多获得一颗星。每输一场,若等级低于20,或在20级且没有一颗星,没有影响,否则减少一颗星。达到lengend级别无论输赢没有任何影响。
代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> using namespace std; typedef long long llt; const int N = 10010; int rk[30]; char data[N]; void init() { for(int i = 21; i <= 25; ++i) rk[i] = 2; for(int i = 16; i <= 20; ++i) rk[i] = 3; for(int i = 11; i <= 15; ++i) rk[i] = 4; for(int i = 1; i <= 10; ++i) rk[i] = 5; } int main() { init(); while(~scanf(" %s",data)){ int r = 25,star = 0; int tick = 0; //没有连续3个w for(int i = 0; i < strlen(data); ++i){ if(data[i] == 'W'){ tick++; if(r == 1 && star == 5){ r = 0; break; } if(tick >= 3 && r >= 6) star += 2; else star++; if(star > rk[r]){ star -= rk[r]; r--; } }else{ tick = 0; if(r > 20 || (r == 20 && star == 0)); else{ if(star == 0){ r++; star = rk[r]-1; }else{ star--; } } } } if(r) printf("%d\n",r); else printf("Legend\n"); } return 0; } /********************************************************************** Problem: 2018 User: zhiyuanjiang Language: C++ Result: AC Time:4 ms Memory:2032 kb **********************************************************************/
解题思路:
水题,比较往哪个方向旋转角度小。
代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <cmath> using namespace std; int main() { int n,m; while(~scanf("%d%d",&n,&m)){ if(n > m) m += 360; int d1 = m-n; int d2 = d1-360; if(abs(d1) < abs(d2)) printf("%d\n",d1); else printf("%d\n",d2); } return 0; } /********************************************************************** Problem: 2025 User: zhiyuanjiang Language: C++ Result: AC Time:0 ms Memory:2024 kb **********************************************************************/