解题思路:
先将题目给定的“黑带”一条条画到图上去,此时可以通过广搜(深搜会爆)得到“联通块”的个数为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
**********************************************************************/
指数循环节,第一次写这种题,一直弄不懂为啥有时不满足那个判断条件的情况下也能用这玩意,数学好难
#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
**********************************************************************/