@meredith233
2017-04-15T00:07:52.000000Z
字数 4867
阅读 744
homework
给定一个二进制数,给定两种操作。操作‘I’对给定区间[a,b]内的数进行取反操作。操作‘Q’查询第i个位置的数是0还是1.
用线段树的区间更新来记录每个位置取反的次数,而后查询时如果取反次数为奇数次则对该数取反。后输出。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define PI acos(-1.0)
#define MAX 100005
using namespace std;
int tre[MAX*4],laz[MAX*4];
char ar[MAX];
void pushdown(int num)
{
if(laz[num]!=0)
{
tre[num*2]+=laz[num];
tre[num*2+1]+=laz[num];
laz[num*2]+=laz[num];
laz[num*2+1]+=laz[num];
laz[num]=0;
}
}
void update(int num,int l,int r,int x,int y)
{
if(x<=l&&y>=r)
{
tre[num]++;
laz[num]++;
return;
}
pushdown(num);
int mid=(l+r)/2;
if(x<=mid)
update(num*2,l,mid,x,y);
if(y>mid)
update(num*2+1,mid+1,r,x,y);
}
int query(int num,int l,int r,int x)
{
if(l==r)
return tre[num];
pushdown(num);
int mid=(l+r)/2;
if(x<=mid)
return query(num*2,l,mid,x);
else
return query(num*2+1,mid+1,r,x);
}
int main()
{
//freopen("test.txt","r",stdin);
int t,cnt=0;
scanf("%d",&t);
while(t--)
{
memset(tre,0,sizeof(tre));
memset(laz,0,sizeof(laz));
scanf("%s",ar+1);
int n=strlen(ar+1);
int q;
printf("Case %d:\n",++cnt);
scanf("%d",&q);
while(q--)
{
char c;
int a,b;
scanf(" %c",&c);
if(c=='I')
{
scanf("%d%d",&a,&b);
update(1,1,n,a,b);
}
if(c=='Q')
{
scanf("%d",&a);
int x=query(1,1,n,a);
int ans=ar[a]-'0';
if(x%2==1)
ans=!ans;
printf("%d\n",ans);
}
}
}
return 0;
}
输入一串数字,然后输入a,b,查询大于等于a且小于等于b的数字有多少个。
二分查找,先对输入的数字串进行排序,后进行两次二分分别查询范围内最小值和最大值所在位置,输出即可。
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int ar[100005];
int main()
{
//freopen("test.txt","r",stdin);
int t,cnt=0;
scanf("%d",&t);
while(t--)
{
int n,q;
scanf("%d%d",&n,&q);
for(int i=0;i<n;i++)
scanf("%d",&ar[i]);
sort(ar,ar+n);
printf("Case %d:\n",++cnt);
while(q--)
{
int a,b;
scanf("%d%d",&a,&b);
int l=0,r=n-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(ar[mid]<a)
l=mid+1;
else
r=mid-1;
}
//cout<<l<<" "<<r<<endl;
a=l;
l=0,r=n-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(ar[mid]<=b)
l=mid+1;
else
r=mid-1;
}
//cout<<l<<" "<<r<<endl;
b=l;
printf("%d\n",b-a);
}
}
return 0;
}
给定一个大圆半径R,以及大圆内的小圆个数n,求小圆的半径r。
连接大圆圆心与相邻两个小圆圆心,可得其角度为2PI/n,而后连接大圆圆心与两小圆心中点,可得公式r=R*sin(PI/n)/(1+sin(PI/n))。在该题中,需要注意在r为整数时输出整数,否则保留10位小数。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#define PI acos(-1.0)
using namespace std;
int main()
{
int t,cnt=0;
scanf("%d",&t);
while(t--)
{
double R,r;
int n;
scanf("%lf%d",&R,&n);
r=R*sin(PI/(double)n)/(1.0+sin(PI/(double)n));
//j
int x=(int)r;
double xx=(double)x;
if(r-xx<1e-12)
printf("Case %d: %.0lf\n",++cnt,r);
else
printf("Case %d: %.10lf\n",++cnt,r);
}
return 0;
}
有n户人,要涂上红,绿,蓝三种颜色,且相邻两户颜色不能相同,给定每户涂每种颜色所需花费,求最小花费。
动态规划,每次求与上一户人家不同颜色时花费最小。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#define PI acos(-1.0)
#define MAX 100005
#define INF (1<<20)
using namespace std;
int ar[25][5],dp[25][5];
int main()
{
int t,cnt=0;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d%d",&ar[i][0],&ar[i][1],&ar[i][2]);
for(int i=0;i<3;i++)
dp[0][i]=ar[0][i];
for(int i=1;i<n;i++)
{
for(int j=0;j<3;j++)
{
if(j==0)
dp[i][j]=ar[i][j]+min(dp[i-1][1],dp[i-1][2]);
if(j==1)
dp[i][j]=ar[i][j]+min(dp[i-1][0],dp[i-1][2]);
if(j==2)
dp[i][j]=ar[i][j]+min(dp[i-1][0],dp[i-1][1]);
}
}
int ans=INF;
for(int i=0;i<3;i++)
ans=min(ans,dp[n-1][i]);
printf("Case %d: %d\n",++cnt,ans);
}
return 0;
}
给定n个数q个查询,求区间最小值。
线段树裸题,求区间最小值。
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAX 100000
#define INF (1<<20)
using namespace std;
int tre[MAX*4];
void build(int num,int l,int r)
{
if(l==r)
{
scanf("%d",&tre[num]);
return;
}
int mid=(l+r)>>1;
build(num*2,l,mid);
build(num*2+1,mid+1,r);
tre[num]=min(tre[num*2],tre[num*2+1]);
}
int query(int num,int l,int r,int x,int y)
{
if(x<=l&&y>=r)
return tre[num];
int mid=(l+r)>>1;
int ans=INF;
if(x<=mid)
ans=min(ans,query(num*2,l,mid,x,y));
if(y>mid)
ans=min(ans,query(num*2+1,mid+1,r,x,y));
return ans;
}
int main()
{
int t,cnt=0;
scanf("%d",&t);
while(t--)
{
int n,q;
scanf("%d%d",&n,&q);
build(1,1,n);
printf("Case %d:\n",++cnt);
while(q--)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",query(1,1,n,a,b));
}
}
return 0;
}
给定一棵树,需要找出树上任意两点间的最长距离。
树的直径问题,先对任一点dfs求出直径的一个端点,后对这个端点求dfs,可得答案。
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define MAX 30005
#define INF (1<<20)
using namespace std;
int n,m,len,dis[MAX],head[MAX],ans,T;
bool vis[MAX];
struct edge
{
int to,val,next;
}e[MAX*2];
void add(int from,int to,int val)
{
e[len].to=to;
e[len].val=val;
e[len].next=head[from];
head[from]=len++;
}
void bfs(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
queue<int>q;
q.push(s);
dis[s]=0;
vis[s]=true;
ans=0;
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=head[cur];i!=-1;i=e[i].next)
{
int id=e[i].to;
if(!vis[id])
{
vis[id]=true;
dis[id]=dis[cur]+e[i].val;
if(ans<dis[id])
{
ans=dis[id];
T=id;
}
q.push(id);
}
}
}
}
int main()
{
int t,cnt=0;
scanf("%d",&t);
while(t--)
{
memset(head,-1,sizeof(head));
len=0;
int n;
scanf("%d",&n);
for(int i=0;i<n-1;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
bfs(0);
bfs(T);
printf("Case %d: %d\n",++cnt,ans);
}
return 0;
}