赞
踩
给定一个十进制自然数的范围和进制的范围,十进制自然数范围在1~44700之间,进制的范围在2~36之间。给定范围里的数中,有些数的平方,在某进制下既是完全平方数又是回文数。本题的任务是统计给定范围内有多少个数的平方满足下列条件:仅在某一进制下既是完全平方数又是回文数。
说明:32=9,因为它在十进制和十一进制中都是回文数,所以9不能算;同样, 262=676也不算。
一行四个整数,分别表示给定的十进制自然数的范围和进制的范围。
一行一个正整数,表示给定范围内满足条件的数的个数。
1 100 9 11
12
【样例说明】
62=36=33 base 11
102= 100= 121 base9
112=121= 121 base 10
122= 144= 121 base 11
202 = 400 = 484 base 9
222= 484 = 484 base 10
242= 576 = 484 base 11
722= 5184 = 3993 base 11
822= 6724= 10201 base 9
842= 7056= 5335 base 11
912= 8281 = 12321 base 9
1002= 10000= 14641 base 9
这是一道无脑的模拟题。只用枚举每一个数,判断这个数在规定的所有进制中是回文数的个数,如果个数为1,表示可以ans+1,否则枚举下一个数。转进制其实很简单,想象一下一个很大的数5546435635664554,把它转化成10进制是怎样做的?
每一步模10再除以10,就是4,5,5,4,6,6,5,3,6,5,3,4,6,4,5,5。然后倒过来就是这个数了。
如果是11进制呢?那么就是模11再除以11.
也就是:4,0,8,5,6,0,4,6,1,1,10,2,7,6,3,1.倒过来就是一个11进制的数了。注意,这里的10表示的是数字,一般在16进制中会用A来表示。
判断是不是回文数,就看第i位数字与第n-i+1位数字是否都是相等。可以先用一个a数组存一下每位数字,然后for循环判断即可。判断回文数的效率也是不可计算的,平均下来大概是一个5左右的常数。
- #include<cstdio>
- using namespace std;
- int l,r,lowest,highest,ans=0,a[1000],len;
- bool check(int p,int q)
- {
- len=0;
- while(p)
- {
- a[++len]=p%q;
- p/=q;
- }
- for(int i=1;i<=len/2;i++)
- if(a[i]!=a[len-i+1]) return false;
- return true;
- }
- int main()
- {
- scanf("%d%d%d%d",&l,&r,&lowest,&highest);
- for(int i=l;i<=r;i++)
- {
- int num=0;
- for(int j=lowest;j<=highest;j++)
- {
- if(check(i*i,j)) num++;
- if(num==2) break;
- }
- if(num==1) ans++;
- }
- printf("%d",ans);
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
有n堆纸牌,编号分别为1,2, ... ,n。每堆上有若干张,但纸牌总数必为n的倍数。可以在任一堆上取若干张纸牌,然后移动。
移牌规则为:在编号为1的堆上取的纸牌,只能移到编号为2的堆上;在编号为n的堆上取的纸牌,只能移到编号为n-1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。
例如n=4,4 堆纸牌数分别为:①9 ②8 ③17 ④6
移动3次可达到目的:
从③取4张牌放到④(9 8 13 10) -> 从③取3张牌放到②(9 11 10 10) -> 从②取1张牌放到①(10 10 10 10)。
n(n堆纸牌,1 <=n<=100)
a1 a2 ... an (n堆纸牌,每堆纸牌初始数,I<=ai <= 10000)
所有堆均达到相等时的最少移动次数。
4
9 8 17 6
3
这道题是一个贪心。可以这样来想:对于最左边的牌,如果没有能达到平均数,那么必然需要与它右边的牌进行交换(可能获得也可能舍去),因此只用记录正负即可。同样的,这个操作能够使最左边的牌数达到平均数(如果第二堆不够可以先欠着,或者说可以从大的牌堆开刀)。然后第二堆就变成了最左边的一堆了,就接着进行以上操作。如果这个堆的牌数已经达到了平均数,就跳过。如此就可以O(n)的完成本题。搜索的话可能会超时一些点。
- #include<cstdio>
- using namespace std;
- int n,a[200],sum=0,ans=0;
- int main()
- {
- scanf("%d",&n);
- for(int i=1;i<=n;i++)
- {
- scanf("%d",&a[i]);
- sum+=a[i];
- }
- sum/=n;
- for(int i=1;i<n;i++)
- {
- if(a[i]==sum) continue;
- ans++;
- a[i+1]+=a[i]-sum;
- }
- printf("%d",ans);
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
某个地区有 n(n<=1000)个犯罪团伙,当地警方按照他们的危险程度由高到低给他们编号为 1-n,他们有些团伙之间有直接联系,但是任意两个团伙都可以通过直接或间接的方式联系,这样这里就形成了一个庞大的犯罪集团,犯罪集团的危险程度由集团内的犯罪团伙数量唯一确定,而与单个犯罪团伙的危险程度无关(该犯罪集团的危险程度为 n)。现在当地警方希望花尽量少的时间(即打击掉尽量少的团伙),使得庞大的犯罪集团分离成若干个较小的集团,并且他们中最大的一个的危险程度不超过 n/2。为达到最好的效果,他们将按顺序打击掉编号 1 到 k 的犯罪团伙,请编程求出 k 的最小值。
第一行一个正整数 n。接下来的 n 行每行有若干个正整数,第一个整数表示该行除第一个外还有多少个整数,若第 i 行存在正整数 k,表示 i,k 两个团伙可以直接联系。
一个正整数,为 k 的最小值
7
2 2 5
3 1 3 4
2 2 4
2 2 3
3 1 6 7
2 5 7
2 5 6
1
【提示】
输出 1(打击掉犯罪团伙)
第一眼看到还以为是找割点,结果想了半天才看到要按照顺序打击范围(-无语-),由于数据范围才1000,直接O(n)枚举k,然后对于每一种情况重新dfs计算连通块的大小,知道第一个小于等于n/2就可以输出答案退出了。注意,已经端掉的犯罪集团VIS应该定为0,然后直接从i+1开始dfs每一块即可。
- #include<cstdio>
- using namespace std;
- struct tree
- {
- int nxt,to;
- }tr[2001000];
- int head[2001000],vis[2000],cnt=0,ans=0;
- int n,m;
- void build_tree(int u,int v)
- {
- tr[++cnt].nxt=head[u];
- tr[cnt].to=v;
- head[u]=cnt;
- }
- void dfs(int k)
- {
- for(int i=head[k];i;i=tr[i].nxt)
- {
- int to=tr[i].to;
- if(vis[to]) continue;
- vis[to]=1;
- ans++;
- dfs(to);
- }
- }
- bool check(int k)
- {
- for(int i=1;i<=k;i++) vis[i]=1;
- for(int i=k+1;i<=n;i++) vis[i]=0;
- for(int i=k+1;i<=n;i++)
- {
- if(vis[i]) continue;
- ans=1;vis[i]=1;dfs(i);
- if(ans>n/2) return false;
- }
- return true;
- }
- int main()
- {
- scanf("%d",&n);
- for(int i=1;i<=n;i++)
- {
- scanf("%d",&m);
- for(int j=1;j<=m;j++)
- {
- int v;scanf("%d",&v);
- build_tree(i,v);
- build_tree(v,i);
- }
- }
- int l=1,r=n;
- for(int i=1;i<=n;i++)
- {
- if(check(i))
- {
- printf("%d",i);
- return 0;
- }
- }
- printf("%d",l);
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
N(1≤N≤1000) 头牛要去参加一场在编号为 x(1≤x≤N)的牛的农场举行的派对。有 M(1≤M≤100000)条有向道路,每条路长 Ti(1≤Ti≤100);每头牛都必须参加完派对后回到家,每头牛都会选择最短路径。求这 N 头牛的最短路径(一个来回)中最长的一条的长度。 特别提醒:可能有权值不同的重边。
第 1 行:3 个空格分开的整数 N,M,X;
第 2…M 行:3 个空格分开的整数 Ai,Bi,Ti ,表示有一条从 Ai 到 Bi 的路,长度为 Ti 。
一行一个数,表示最长最短路的长度。
4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3
10
由于一头牛从本家通向x,走的是最短距离,再从x回家,走最短距离。因此可以想象都是由x出发,建一个正图,一个反图,代表来回,然后直接以x作为初始节点求一个单源最短路,然后对于每一个非x的点,求一下两个最小值的和,然后取max就可以了。
- #include<cstring>
- #include<cstdio>
- #include<queue>
- using namespace std;
- queue<int>q;
- int n,m,x;
- struct tree
- {
- int nxt,to,dis;
- };
- tree tr1[100100],tr2[100100];
- int head1[100100],cnt1=0,vis1[2000],di1[2000],ans=0;
- int head2[100100],cnt2=0,vis2[2000],di2[2000];
- void build_tree(int u,int v,int d)
- {
- tr1[++cnt1].nxt=head1[u];
- tr1[cnt1].to=v;
- tr1[cnt1].dis=d;
- head1[u]=cnt1;
- tr2[++cnt2].nxt=head2[v];
- tr2[cnt2].to=u;
- tr2[cnt2].dis=d;
- head2[v]=cnt2;
- }
- int main()
- {
- memset(di1,127/3,sizeof(di1));
- memset(di2,127/3,sizeof(di2));
- scanf("%d%d%d",&n,&m,&x);
- while(m--)
- {
- int u,v,d;
- scanf("%d%d%d",&u,&v,&d);
- build_tree(u,v,d);
- }
- q.push(x);vis1[x]=1;di1[x]=0;
- while(!q.empty())
- {
- int pt=q.front();q.pop();
- vis1[pt]=0;
- for(int i=head1[pt];i;i=tr1[i].nxt)
- {
- int to=tr1[i].to,dis=tr1[i].dis;
- if(di1[to]>di1[pt]+dis)
- {
- di1[to]=di1[pt]+dis;
- if(!vis1[to])
- {
- vis1[to]=1;
- q.push(to);
- }
- }
- }
- }
- q.push(x);vis2[x]=1;di2[x]=0;
- while(!q.empty())
- {
- int pt=q.front();q.pop();
- vis2[pt]=0;
- for(int i=head2[pt];i;i=tr2[i].nxt)
- {
- int to=tr2[i].to,dis=tr2[i].dis;
- if(di2[to]>di2[pt]+dis)
- {
- di2[to]=di2[pt]+dis;
- if(!vis2[to])
- {
- vis2[to]=1;
- q.push(to);
- }
- }
- }
- }
- for(int i=1;i<=n;i++)
- {
- if(i==x) continue;
- if(di1[i]+di2[i]>ans) ans=di1[i]+di2[i];
- }
- printf("%d",ans);
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
一树上有 n 个节点,编号分别为 1 到 n,每个节点都有一个权值 w。我们将以下面的形式来要求你对这棵树完成一些操作:
1. CHANGE u t :把节点 u 权值改为 t;
2. QMAX u v :询问点 u 到点 v 路径上的节点的最大权值;
3. QSUM u v :询问点 u 到点 v 路径上的节点的权值和。
注意:从点 u 到点 v 路径上的节点包括 u 和 v 本身。
第一行为一个数 n,表示节点个数;
接下来 n-1 行,每行两个整数 a,b,表示节点 a 与节点 b 之间有一条边相连;
接下来 n 行,每行一个整数,第 i 行的整数 wi 表示节点 i 的权值;
接下来一行,为一个整数 q ,表示操作总数;
接下来 q 行,每行一个操作,以 CHANGE u t 或 QMAX u v 或 QSUM u v的形式给出。
对于每个 QMAX 或 QSUM 的操作,每行输出一个整数表示要求的结果。
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
4
1
2
2
10
6
5
6
5
16
【数据范围与提示】
对于 100% 的数据,有 1≤n≤3×104 ,0≤q≤2×105 。
中途操作中保证每个节点的权值 w 在 -30000 至 30000 之间。
树链剖分板题有没有?这里就是一个。写一个能单点修改、查询区间最值、查询区间和的线段树,然后写一个树链剖分进行更改即可。如果不知何为“线段树”、何为“树链剖分”,可查查百度。(特别注意:debug了一个小时,结果是top[x]!=top[y]我把while写成了if,导致样例能对,但是只能过20分,特别要小心!!)
- #include<cstdio>
- #define lc (x<<1)
- #define rc (x<<1|1)
- #define MAXN 100001
- #define LL long long
- using namespace std;
- struct tree1
- {
- int nxt,to;
- }tr[MAXN*2];
- struct tree2
- {
- int l,r;LL sum,mx;
- }ask[MAXN*4];
- char s[200];
- LL a[MAXN];
- int head[MAXN*2],cnt=0,tot=0,n,m;
- int son[MAXN],fa[MAXN],dep[MAXN],size[MAXN];
- int seg[MAXN],rev[MAXN],top[MAXN];
- LL max1(LL p,LL q) { return p>q?p:q; }
- int swap1(int & p,int & q)
- { int c=p;p=q;q=c; }
- void make_tree(int x,int l,int r)
- {
- ask[x].l=l;ask[x].r=r;
- if(l==r)
- {
- ask[x].mx=ask[x].sum=a[rev[l]];
- return;
- }
- int mid=(l+r)/2;
- make_tree(lc,l,mid);
- make_tree(rc,mid+1,r);
- ask[x].sum=ask[lc].sum+ask[rc].sum;
- ask[x].mx=max1(ask[lc].mx,ask[rc].mx);
- }
- void update(int x,int pos,LL k)
- {
- if(ask[x].l==ask[x].r)
- {
- ask[x].mx=ask[x].sum=k;
- return ;
- }
- int mid=(ask[x].l+ask[x].r)/2;
- if(pos<=mid) update(lc,pos,k);
- else update(rc,pos,k);
- ask[x].sum=ask[lc].sum+ask[rc].sum;
- ask[x].mx=max1(ask[lc].mx,ask[rc].mx);
- }
- LL query_sum(int x,int l,int r)
- {
- if(ask[x].l>r||ask[x].r<l) return 0;
- if(ask[x].l>=l&&ask[x].r<=r) return ask[x].sum;
- return query_sum(lc,l,r)+query_sum(rc,l,r);
- }
- LL query_max(int x,int l,int r)
- {
- if(ask[x].l>r||ask[x].r<l) return 1ll<<63;
- if(ask[x].l>=l&&ask[x].r<=r) return ask[x].mx;
- return max1(query_max(lc,l,r),query_max(rc,l,r));
- }
- void build_tree(int u,int v)
- {
- tr[++cnt].nxt=head[u];
- tr[cnt].to=v;
- head[u]=cnt;
- }
- void dfs1(int k,int f)
- {
- size[k]=1;
- for(int i=head[k];i;i=tr[i].nxt)
- {
- int to=tr[i].to;
- if(to==f) continue;
- fa[to]=k;
- dep[to]=dep[k]+1;
- dfs1(to,k);
- size[k]+=size[to];
- if(size[to]>size[son[k]])
- son[k]=to;
- }
- }
- void dfs2(int k,int f)
- {
- seg[k]=++tot;
- rev[tot]=k;
- if(son[k])
- {
- top[son[k]]=top[k];
- dfs2(son[k],k);
- }
- for(int i=head[k];i;i=tr[i].nxt)
- {
- int to=tr[i].to;
- if(to==f) continue;
- if(top[to]==0)
- {
- top[to]=to;
- dfs2(to,k);
- }
- }
- }
- LL ask_sum(int x,int y)
- {
- LL ans=0;
- while(top[x]!=top[y])
- {
- if(dep[top[x]]<dep[top[y]])
- swap1(x,y);
- ans+=query_sum(1,seg[top[x]],seg[x]);
- x=fa[top[x]];
- }
- if(dep[x]>dep[y]) swap1(x,y);
- ans+=query_sum(1,seg[x],seg[y]);
- return ans;
- }
- LL ask_max(int x,int y)
- {
- LL maxn=1ll<<63;
- while(top[x]!=top[y])
- {
- if(dep[top[x]]<dep[top[y]])
- swap1(x,y);
- maxn=max1(maxn,query_max(1,seg[top[x]],seg[x]));
- x=fa[top[x]];
- }
- if(dep[x]>dep[y]) swap1(x,y);
- maxn=max1(maxn,query_max(1,seg[x],seg[y]));
- return maxn;
- }
- int main()
- {
- scanf("%d",&n);
- for(int i=1;i<n;i++)
- {
- int u,v;
- scanf("%d%d",&u,&v);
- build_tree(u,v);
- build_tree(v,u);
- }
- for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
- fa[1]=top[1]=dep[1]=1;
- dfs1(1,0),dfs2(1,0);
- make_tree(1,1,n);
- scanf("%d",&m);
- while(m--)
- {
- scanf("%s",s);
- if(s[1]=='M')
- {
- int l,r;
- scanf("%d%d",&l,&r);
- printf("%lld\n",ask_max(l,r));
- }
- else if(s[1]=='S')
- {
- int l,r;
- scanf("%d%d",&l,&r);
- printf("%lld\n",ask_sum(l,r));
- }
- else if(s[1]=='H')
- {
- LL k;int pos;
- scanf("%d%lld",&pos,&k);
- update(1,seg[pos],k);
- }
- }
- return 0;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。