题目描述
略
输入
第一行输入一个数字 。
第二行输入n个数字,第i个数字为ai,以空格隔开。
接下来输入n行询问,每行输入四个数字opt 、l、r、c,以空格隔开。
若 opt=1表示将位于l-r 的之间的数字都加c 。
若 opt=0表示询问l-r的值。
输出
对于每次询问,输出一行一个数字表示答案。
题目分析
本题是一道板子题。涉及区间加法和单点查询。
所以:暴力必TLE。由此用分块可以解决这个问题
PS :分块过程中可能会遇到l~r距离小于block的情况
CODE:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
int wadd[ 10100 ] , A[ 500010 ] , ans[ 500010 ] , t, cnt= 0 ;
int QRead ( ) {
int x= 0 , f= 1 ; char c= getchar ( ) ;
while ( c< '0' || c> '9' ) { if ( c== '-' ) f= - 1 ; c= getchar ( ) ; }
while ( c<= '9' && c>= '0' ) { x= x* 10 + c- '0' ; c= getchar ( ) ; }
return x* f;
}
int void1 ( ) {
int l= QRead ( ) , r= QRead ( ) , c= QRead ( ) ;
int l1, r1;
if ( l% t== 0 ) { l1= ( l/ t) + 1 ; } else l1= ( l/ t) + 2 ;
if ( r% t== 0 ) { r1= ( r/ t) - 1 ; } else r1= r/ t;
if ( r- l> t) {
for ( int i= l1; i<= r1; ++ i)
wadd[ i] + = c;
int r2= ( l1- 1 ) * t; int l2= r1* t+ 1 ;
for ( int i= l; i<= r2; ++ i)
A[ i] + = c;
for ( int i= l2; i<= r; ++ i)
A[ i] + = c;
}
else {
for ( int i= l; i<= r; ++ i) {
A[ i] + = c;
}
}
return 0 ;
}
int void2 ( ) {
int l= QRead ( ) , r= QRead ( ) , c= QRead ( ) ;
if ( r% t== 0 ) ans[ ++ cnt] = A[ r] + wadd[ r/ t] ;
else ans[ ++ cnt] = A[ r] + wadd[ ( r/ t) + 1 ] ;
return 0 ;
}
int main ( ) {
int n= QRead ( ) ;
t= sqrt ( n) ;
for ( int i= 1 ; i<= n; ++ i)
A[ i] = QRead ( ) ;
for ( int i= 1 ; i<= n; ++ i) {
int p= QRead ( ) ;
if ( p) void2 ( ) ;
else void1 ( ) ;
}
for ( int i= 1 ; i<= cnt; ++ i) {
printf ( "%d\n" , ans[ i] ) ;
}
return 0 ;
}
回顾反思
/与%是两个符号 记得要删调试
L
L
L 之后是被操作的范围,
R
R
R 之前是被操作的范围
L
L
L ~
R
R
R 之间距离可能小于每块长度
题目描述:
小 Z 把这 N 只袜子从1到 N 编号,然后从编号L到R尽管小 Z 并不在意两只袜子是不是完整的一双,甚至不
在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。你的任务便是告诉小 Z,
他有多大的概率抽到两只颜色相同的袜子。当然,小 Z 希望这个概率尽量高,所以他可能会询问多个L,R以方便自
己选择。然而数据中有L=R 的情况,请特判这种情况,输出0/1。
输入&输出:
输入文件第一行包含两个正整数N和M。N为袜子的数量,M 为小 Z 所提的询问的数量。接下来一行包含N 个正整
数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同的数字表示。再接下来M行,每行两个正整数 L, R 表示一
个询问。包含 M 行,对于每个询问在一行中输出分数 A/B 表示从该询问的区间 [L,R] 中随机抽出两只袜子颜色相
同的概率。若该概率为 0 则输出 0/1,否则输出的 A/B 必须为最简分数。
题目分析:
由题意可知需将相同颜色的袜子统计出来,同时计算出可能发生的所有事件。由数学知识可得在长为 N 的数列中
排列组合(不分先后)共有 X=(n*n-n)/2 种情况。于是套板。
CODE:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
ll leh, c[ 50050 ] , cnt[ 50050 ] , ans= 0 ;
struct node{
ll l, r, num, a, b;
} Qt[ 50050 ] ;
inline ll QRead ( ) {
ll x= 0 , f= 1 ; char c= getchar ( ) ;
while ( c> '9' || c< '0' ) { if ( c== '-' ) f= - 1 ; c= getchar ( ) ; }
while ( c<= '9' && c>= '0' ) { x= x* 10 + c- '0' ; c= getchar ( ) ; }
return f* x;
}
bool cmp1 ( node a, node b) {
return ( a. r/ leh) == ( b. r/ leh) ? a. l< b. l: a. r< b. r;
}
bool cmp2 ( node a, node b) {
return a. num< b. num;
}
inline void add ( int x) {
ans + = cnt[ c[ x] ] ;
cnt[ c[ x] ] ++ ;
}
inline void dlt ( int x) {
cnt[ c[ x] ] -- ;
ans - = cnt[ c[ x] ] ;
}
inline ll gcd ( int a, int b) {
return b? gcd ( b, a% b) : a;
}
int main ( ) {
int N= QRead ( ) , M= QRead ( ) ;
leh = sqrt ( N) ;
for ( int i= 1 ; i<= N; ++ i) {
c[ i] = QRead ( ) ;
}
for ( int i= 1 ; i<= M; ++ i) {
Qt[ i] . l= QRead ( ) ;
Qt[ i] . r= QRead ( ) ;
Qt[ i] . num= i;
}
sort ( Qt+ 1 , Qt+ M+ 1 , cmp1) ;
int l1= 1 , r1= 0 ;
for ( int i= 1 ; i<= M; ++ i) {
int Ql= Qt[ i] . l, Qr= Qt[ i] . r;
while ( l1< Ql) { dlt ( l1) ; l1++ ; }
while ( l1> Ql) { l1-- ; add ( l1) ; }
while ( r1< Qr) { r1++ ; add ( r1) ; }
while ( r1> Qr) { dlt ( r1) ; r1-- ; }
Qt[ i] . a= ans;
Qt[ i] . b= ( Qt[ i] . r- Qt[ i] . l) * ( Qt[ i] . r- Qt[ i] . l+ 1 ) / 2 ;
if ( ! ans) { Qt[ i] . b= 1 ; continue ; }
int gcdi= gcd ( Qt[ i] . a, Qt[ i] . b) ;
Qt[ i] . a/ = gcdi; Qt[ i] . b/ = gcdi;
}
sort ( Qt+ 1 , Qt+ M+ 1 , cmp2) ;
for ( int i= 1 ; i<= M; ++ i) {
printf ( "%lld/%lld\n" , Qt[ i] . a, Qt[ i] . b) ;
}
return 0 ;
}
反思与总结:
数据可能过大 注意三目运算符