A. Coder
题意:在一张网格上放置棋子,他能攻击到上下左右的地方,问最多放多少棋子,使其不能相互攻击到,输出一种方法;
思路:从第一个开始放,标记其上下左右。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1005;
char grid[maxn][maxn];
bool vis[maxn][maxn];
int n,ans;
void init()
{
ans=1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
grid[i][j]='.';
vis[i][j]=false;
}
}
int main()
{
cin>>n;
init();
grid[1][1]='C';
vis[1][1]=vis[1][2]=vis[2][1]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(!vis[i][j])
{
grid[i][j]='C';
ans++;
vis[i][j]=vis[i+1][j]=vis[i-1][j]=vis[i][j-1]=vis[i][j+1]=1;
}
}
cout<<ans<<endl;
for(int i=1;i<=n;i++)
cout<<grid[i]+1<<endl;
return 0;
}
B. Multitasking
思路:直接模拟,刚开始算错复杂度了,应该是m^2*n,想成n^2*m了,按步骤最多的写就可以了,后来看了别人的代码,瞬间感觉弱爆了,直接输出就可以。。。
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 102;
int g[maxn][maxn];
int r[maxn];
struct node{
int ll, rr;
}q[maxn * maxn];
int main(){
int n, m, k;
while (scanf("%d %d %d",&n,&m,&k)!=EOF){
int a, b;
for (int i=0; i<n; i++){
for (int j=0; j<m; j++){
scanf("%d",&r[j]);
}
for (int j=0; j<m; j++){
for (int l=j+1; l<m; l++){
if (k == 0 && r[j] > r[l]){
g[j][l] = 1;
}
if (k == 1 && r[j] < r[l]){
g[l][j] = 1;
}
}
}
}
int tp = 0;
for (int i=0; i<m; i++){
for (int j=0; j<m; j++){
if (g[i][j]){
q[tp].ll = i;
q[tp++].rr = j;
}
}
}
printf("%d\n",tp);
for (int i=0; i<tp; i++){
printf("%d %d\n",q[i].ll+1,q[i].rr+1);
}
}
return 0;
}
#include <cstdio>
using namespace std;
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
printf("%d\n",(m*m-m)/2);
for(int i=1;i<=m;i++)
for(int j=i+1;j<=m;j++)
if(k==0)
printf("%d %d\n",i,j);
else
printf("%d %d\n",j,i);
return 0;
}
C. Milking cows
思路:只需要计算每头朝左的牛右边所有朝右的牛的个数,然后求和就可以。或者反过来算也行。
#include<iostream>
using namespace std;
typedef long long LL;
LL n,ans,sum;
int main()
{
cin>>n;
ans=sum=0;
int k;
for(int i=0;i<n;i++)
{
cin>>k;
if(k==1)
sum++;
else ans+=sum;
}
cout<<ans<<endl;
return 0;
}
E. Propagating tree(参考)
题意:有一颗n个结点的有根树,每个结点有一个值a[i],可以对树进行以下两种操作:
1、"1 x val" 把结点x的值加val,同时把结点x的儿子的值加上-val,结点x的儿子的儿子加上val,等等依次这样进行
2、"2 x"查询结点x的值
思路:由于第一个操作是对整个以x为根的子树进行修改,因此我们可以利用dfs序把整个子树重新编号为连续的区间,然后与结点x的树高的奇偶性相同的儿子结点是加val,否则就是加-val,一般我们我们遇到的区间操作都是,对某个区间进行同一种修改操作,但是此题是结点的奇偶性不同,操作不同,如果我们用一颗线段树或者树状数组的话搞起来很麻烦,我们可以根据结点的奇偶搞两颗BIT,然后根据结点x的奇偶性对对应的BIT进行相应的区间修改操作,查询也是根据结点的奇偶性在对应的BIT上进行查询
下面是代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=200100;
struct node
{
int v,next;
}edge[2*maxn];
int n,m,step=0,num=1;
int deg[maxn],high[maxn],tree[2][maxn],vis[maxn],low[maxn],a[maxn],head[maxn];
void add_edge(int u,int v)
{
edge[num].v=v;
edge[num].next=head[u];
head[u]=num++;
}
void dfs(int u,int flag)
{
low[u]=++step;//记录到达当前节点的时间
deg[u]=flag;//标记当前节点的奇偶性
vis[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next)
{
if(!vis[edge[i].v])
dfs(edge[i].v,(flag+1)%2);
}
high[u]=step;//记录当前节点能管辖的范围
}
void add(int x,int val,int flag)
{
while(x<=n)
{
tree[flag][x]+=val;
x+=x&(-x);
}
}
int sum(int x,int flag)
{
int ans=0;
while(x>0)
{
ans+=tree[flag][x];
x-=x&(-x);
}
return ans;
}
int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(head,-1,sizeof(head));
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
}
memset(vis,0,sizeof(vis));
memset(tree,0,sizeof(tree));
dfs(1,0);
int op,x,val;
for(int i=0;i<m;i++)
{
scanf("%d%d",&op,&x);
if(op==1)
{
scanf("%d",&val);
add(low[x],val,deg[x]);
add(high[x]+1,-val,deg[x]);
add(low[x],-val,(deg[x]+1)%2);
add(high[x]+1,val,(deg[x]+1)%2);
}
else cout<<a[x]+sum(low[x],deg[x])<<endl;
}
return 0;
}