感谢Okkkkkkkkk大神的指点!!真心ORZ
博主好久都没有更新了(期末考试蹦蹦蹦!!!差点被劝退竞赛……)然后呢,最近又在刷uscao与LA(英语不及格全靠谷歌翻译……),但是今天偶然在洛谷看见一场比赛,很有趣……于是……邀请竞赛队员(一堆洛谷灰名怒刷4题)
本人认为难度从小到大为3<2<4<1
题目
区间方差
https://www.luogu.org/problem/show?pid=T2005
作为代码实现最难题,这道题一开始我使用线段树加快速幂或扩展欧几里得900ms+解决的
/**
* luogu.org
* Problem#2005
* Accepted
* Time:965ms
* Memory:18601k
*/
#include<iostream>
#include<fstream>
#include<sstream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef bool boolean;
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline void readInteger(T& u){
char x;
int aFlag = 1;
while(!isdigit((x = getchar())) && x != '-' && x != -1);
if(x == -1) return;
if(x == '-'){
x = getchar();
aFlag = -1;
}
for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
ungetc(x, stdin);
u *= aFlag;
}
const int moder = 1000000007;
template<typename T1, typename T2>
class Pair{
public:
T1 x;
T2 y;
Pair(T1 x, T2 y):x(x), y(y){ }
Pair operator +(Pair another){
return Pair(x + another.x % moder, y + another.y % moder);
}
};
typedef class TreeNode{
public:
int sum;
int sum2;
int from, end;
TreeNode* left, *right;
TreeNode(long long sum, int from, int end):from(from), end(end), left(NULL), right(NULL), sum(sum){
sum2 = sum * sum % moder;
}
void pushUp(){
this->sum = this->left->sum + this->right->sum;
this->sum %= moder;
this->sum2 = this->left->sum2 + this->right->sum2;
this->sum2 %= moder;
}
}TreeNode;
typedef class SegTree{
public:
TreeNode* root;
SegTree():root(NULL){ }
SegTree(int size, int* val){
build(root, 1, size, val);
}
void build(TreeNode*& node, int from, int end, int* val){
node = new TreeNode(0, from, end);
if(from == end){
node->sum = val[from];
node->sum2 = (int)(val[from] * 1LL * val[from] % moder);
return;
}
int mid = (from + end) >> 1;
build(node->left, from, mid, val);
build(node->right, mid + 1, end, val);
node->pushUp();
}
void update(TreeNode*& node, int index, int val){
if(node->from == index && node->end == index){
node->sum = val;
node->sum2 = (int)(val * 1LL * val % moder);
return;
}
int mid = (node->from + node->end) >> 1;
if(index <= mid) update(node->left, index, val);
else update(node->right, index, val);
node->pushUp();
}
Pair<long long, long long> query(TreeNode*& node, int from, int end){
if(node->from == from && node->end == end){
return Pair<long long, long long>(node->sum, node->sum2);
}
int mid = (node->from + node->end) >> 1;
if(end <= mid) return query(node->left, from, end);
if(from > mid) return query(node->right, from, end);
return query(node->left, from, mid) + query(node->right, mid + 1, end);
}
}SegTree;
/*
int pow_mod(int x, int pos){
if(pos == 1) return x;
int temp = pow_mod(x, pos / 2);
if(pos & 1) return (int)(temp * 1LL * temp % moder * x % moder);
return (int)(temp * 1LL * temp % moder);
}
*/
void gcd(int a, int b, int& d, int& x, int& y){
if(b == 0){
d = a;x = 1;y= 0;
}else{ gcd(b, a % b, d, y, x); y -= x * (a / b); }
}
int getInv(int a, int n){
int d, x, y;
gcd(a, n, d, x, y);
return (x + n) % n;
}
int n, m;
SegTree st;
int* initer;
inline void init(){
readInteger(n);
readInteger(m);
initer = new int[(const int)(n + 1)];
for(int i = 1; i <= n; i++)
readInteger(initer[i]);
st = SegTree(n, initer);
}
inline void solve(){
int op, a, b;
while(m--){
readInteger(op);
readInteger(a);
readInteger(b);
if(op == 1){
st.update(st.root, a, b);
}else if(op == 2){
Pair<long long, long long> p = st.query(st.root, a, b);
long long L = b - a + 1;
// long long inv = pow_mod(L * L % moder, moder - 2);
int inv = getInv(L * L % moder, moder);
long long fm = (L * (p.y % moder) % moder - p.x * p.x % moder + moder) % moder;
long long ans = fm * inv % moder;;
cout << ans << endl;
}
}
}
int main(){
init();
solve();
return 0;
}
但是发现出题人有之前的优化方案:
https://www.luogu.org/discuss/show?postid=7330
加上读入优化后达到了500ms+
但是这并不能满足我的野心(优化到第一份代码时间1/2以下),所以……和我厚颜无耻地找出题人要了代码研究(copy……)
其实并没有什么大的改变
#include<cstdio>
typedef long long ll;
const int maxn=100005,mod=1e9+7;
ll rev[maxn],s[maxn],sq[maxn],num[maxn],y,t,ch;
int n,m,c,x,len;
ll Mod(ll x)
{
while(x>=mod)x-=mod;//就这一处值了200ms+!!!!
while(x<0)x+=mod;
return x;
}
void add(ll*b,int p,ll v){for(;p<=n;p+=p&-p)b[p]=Mod(b[p]+v);}
ll ask(ll*b,int p)
{
ll ans=0;
for(;p;p-=p&-p)ans=Mod(ans+b[p]);
return ans;
}
ll ask(ll*b,int x,int y){return ask(b,y)-ask(b,x-1);}
void read(int&x)
{
x=0,ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
}
void read(ll&x)
{
x=0,ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
}
int main()
{
read(n),read(m);
rev[1]=1;for(register int i=2;i<=n;++i)rev[i]=(mod-mod/i)*rev[mod%i]%mod;
for(register int i=1;i<=n;++i)read(num[i]),add(s,i,num[i]),add(sq,i,num[i]*num[i]%mod);
while(m--)
{
read(c),read(x),read(y);
if(c==1)
{
add(s,x,Mod(y-num[x]));
add(sq,x,Mod(y*y%mod-num[x]*num[x]%mod));
num[x]=y;
}
else
{
len=y-x+1;t=ask(s,x,y)*rev[len]%mod;
printf("%lld\n",Mod((rev[len]*ask(sq,x,y)%mod-t*t%mod)));
}
}
return 0;
}
至今原因不明………………
漂浮的鸭子
https://www.luogu.org/problem/show?pid=T2049
一开始算法学傻了……就知道Trajan……
所以很慢…………
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define rez(i,x,y) for(int i=x;i>=y;i--)
#define res(i,x,y) for(int i=x;i<=y;i++)
#define INF 2100000000
#define ll long long
#define NAME "scc"
#define clr(x) memset(x,0,sizeof(x))
#define maxn 1000005
using namespace std;
template <class T>
inline int readin(T &res){
static char ch;
while ((ch = getchar()) < '0' || ch > '9');
res = ch - 48;
while ((ch = getchar()) >= '0' && ch <= '9')
res = res * 10 + ch - 48;
}
vector<int> G[maxn];
int pre[maxn],lowlink[maxn],sccon[maxn],num[maxn],val[maxn],b[maxn];
int n,dfs_clock,scc_cnt,total;
stack<int> S;
void dfs(int u){
pre[u]=lowlink[u]=++dfs_clock;
S.push(u);
for(ll i=0;i<G[u].size();i++){
int v=G[u][i];
if(!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}else if(!sccon[v]){
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if(lowlink[u]==pre[u]){
scc_cnt++;
while(1){
ll x=S.top();S.pop();
sccon[x]=scc_cnt;
if(x==u)break;
}
}
}
void find_scc(int n){
dfs_clock=scc_cnt=0;
clr(sccon);
clr(pre);
for(ll i=0;i<n;i++){
if(!pre[i])dfs(i);
}
}
int main(){
readin(n);
for(int y,x,i=1;i<=n;i++){
readin(x);readin(val[i]);
G[i].push_back(x);
}
find_scc(n);
for(int i=1;i<=n;i++){
total=max(total,sccon[i]);
num[sccon[i]]+=val[i];
b[sccon[i]]++;
}
int ans=0;
for(int i=1;i<=total;i++){
if(b[i]>1)ans=max(ans,num[i]);
}
cout<<ans<<endl;
return 0;
}
然后一位刚刚开始学树的同学用搜索…………
快爆了!!!!
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100000+10;
int n, D[MAXN], T[MAXN], tvolk=0, time[MAXN], volk[MAXN], tim=0;
void search(int volki, int i, int papa)
{
volk[i]=volki;
time[i]=time[papa]+T[papa];
if (!volk[D[i]]) search(volki,D[i],i);
else if (volk[i]==volk[D[i]])tim=max(tim,time[i]+T[i]-time[D[i]]);
}
int main()
{
memset(time,0,sizeof(time));
memset(volk,0,sizeof(volk));
scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%d%d",&D[i],&T[i]);
for (int i=1; i<=n; i++) if (!volk[i]) search(++tvolk,i,0);
printf("%d\n",tim);
return 0;
}
看来NOIP没有得一等奖是有原因的。
最大差值
https://www.luogu.org/problem/show?pid=T2061
水水水水水水!!!!
//打擂台思想,贪心
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define rez(i,x,y) for(int i=x;i>=y;i--)
#define res(i,x,y) for(int i=x;i<=y;i++)
#define INF 2100000000
#define ll long long
#define clr(x) memset(x,0,sizeof(x))
using namespace std;
template <class T> inline void readin(T &xx)
{
xx = 0;
T flag = 1;
char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
xx = (xx<<1) + (xx<<3) + ch - '0';
ch = (char)getchar();
}
xx *= flag;
}
int x,n,minn,tot;
int main(){
readin(n);
for(int i=1;i<=n;i++){
readin(x);
if(i==1)minn=x;
else{
if(x>minn)tot=max(tot,x-minn);
else minn=x;
}
}
printf("%d\n",tot);
return 0;
}
随机数生成器
看到题目我就感到了来自数论的不友善的目光…………
惯用手段!!打表万岁
90code
//表的生成器
#include<iostream>
#include<cstdio>
#include<cstdlib>
#define rez(i,x,y) for(int i=x;i>=y;i--)
#define res(i,x,y) for(int i=x;i<=y;i++)
#define INF 2100000000
#define ll long long
#define clr(x) memset(x,0,sizeof(x))
#define maxn 1000005
using namespace std;
double st=23.063621,p=47326467160.266045,t=47326467160.266045;
int main(){
//freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
for(ll i=2145000000LL;i<2300000000LL;i++){
st=(t+i)/(i-1),p+=st,t=p;
if((i/5000000LL)>439&&i%5000000LL==0){
printf("else if(x/5000000==%I64d)st=%lf,p=%lf,t=%lf;\n",i/5000000LL,st,p,t);
}
}
return 0;
}
t请自动忽略,纯属脑抽。
不知道为什么T9就是过不去,绝对有毒…………
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define rez(i,x,y) for(int i=x;i>=y;i--)
#define res(i,x,y) for(int i=x;i<=y;i++)
#define INF 2100000000
#define ll long long
#define clr(x) memset(x,0,sizeof(x))
#define maxn 1000005
using namespace std;
template <class T>
inline int readin(T &res){
static char ch;
while ((ch = getchar()) < '0' || ch > '9');
res = ch - 48;
while ((ch = getchar()) >= '0' && ch <= '9')
res = res * 10 + ch - 48;
}
int x;
double st=0,p=0,t=0;
int main(){
cin>>x;
if(x/5000000==0){
for(int i=2;i<=x;i++){
st=(t+i)/(i-1),p+=st,t=p;
}
printf("%0.5lf",st);
return 0;
}
else if(x/5000000==1)st=17.002164,p=80010820.176497,t=80010820.176497;
else if(x/5000000==2)st=17.695311,p=166953112.658580,t=166953112.658580;
else if(x/5000000==3)st=18.100776,p=256511645.859481,t=256511645.859481;
else if(x/5000000==4)st=18.388458,p=347769169.428388,t=347769169.428388;
else if(x/5000000==5)st=18.611602,p=440290050.693344,t=440290050.693344;
else if(x/5000000==6)st=18.793924,p=533817707.635781,t=533817707.635781;
else if(x/5000000==7)st=18.948074,p=628182599.452376,t=628182599.452376;
else if(x/5000000==8)st=19.081606,p=723264226.579084,t=723264226.579084;
else if(x/5000000==9)st=19.199389,p=818972491.568537,t=818972491.568537;
else if(x/5000000==10)st=19.304749,p=915237460.914611,t=915237460.914611;
else if(x/5000000==11)st=19.400059,p=1012003266.945319,t=1012003266.945319;
else if(x/5000000==12)st=19.487071,p=1109224246.605193,t=1109224246.605193;
else if(x/5000000==13)st=19.567113,p=1206862376.529425,t=1206862376.529425;
else if(x/5000000==14)st=19.641221,p=1304885502.043997,t=1304885502.043997;
else if(x/5000000==15)st=19.710214,p=1403266074.730120,t=1403266074.730120;
else if(x/5000000==16)st=19.774753,p=1501980228.103149,t=1501980228.103149;
else if(x/5000000==17)st=19.835377,p=1601007085.245298,t=1601007085.245298;
else if(x/5000000==18)st=19.892536,p=1700328229.887734,t=1700328229.887734;
//******^^^^^^^^23333333333333333333333333333333333完整表就不放完了,明白就好
else if(x/5000000==424)st=23.051898,p=46750022890.877975,t=46750022890.877975;
else if(x/5000000==425)st=23.054253,p=46865288270.431168,t=46865288270.431168;
else if(x/5000000==426)st=23.056603,p=46980565414.694550,t=46980565414.694550;
else if(x/5000000==427)st=23.058948,p=47095854296.046997,t=47095854296.046997;
else if(x/5000000==428)st=23.061287,p=47211154887.035942,t=47211154887.035942;
else if(x/5000000==429)st=23.063621,p=47326467160.266045,t=47326467160.266045;
else if(x/5000000==430)st=23.065949,p=47441791111.636383,t=47441791111.636383;
int sum=(x/5000000)*5000000;
while(sum<=x){
++sum;
st=(t+sum)/(sum-1),p+=st,t=p;
}
printf("%0.5lf",st);
return 0;
}
打表还是我这个蒟蒻的强项啊!!!
但没有这个式子:st=(p+sum)/(sum-1),p+=st,我也做不出来。
然后我不服……我曾经可是数竞的啊!!!
所以狡诈了一下……
#include <cstdio>
#include <cmath>
int n;
double w=2;
int main(){
scanf("%d",&n);
if (n>10000000){
printf("%0.5lf\n",1.57721566490123286060651209+log(n-1));
return 0;
}
else if (n==1) printf("0.00000");
else
{
for (int i=3; i<=n; i++) w+=1.0/(i-1);
printf("%0.5lf\n",w);
}
return 0;
}
//0.57721566490123286060651209
0.57721566490123286060651209……是什么呢?欧拉常数。
有什么用呢?作用如上。
原理?http://baike.baidu.com/link?url=s-Bo62nMcueyWPeSZumHgR7Y8s3RuPEsbcUyrbkw7ttbNvPv5xA-wj8PwTpdg2ZzEnKp53v5ET74f8Sl89oChFGqbbnDUlzroYF1Rc0GGTTyP5P6B3dZG51FxB325RSM 自己看吧。
好嘞,苟日新,日日新,又日新。
#1就是我!!MVP!!。
#2就是无私而又伟大的出题人。
#3#4#10都是我们学校的人。
是不是发现没有每日推荐?恩,的却是这样啊,但是看看图。
那就算了吧。。。。
错了错了
推荐吧
六花的勇者(推理+悬疑,情节波澜起伏,不被剧透的话,很令人震撼)
http://baike.baidu.com/link?url=lnH3BxhkC4O1RMVVjqi5x8nhQrkLwzdSpIQbj2iFNVvbjsB_ebKBeMhiUBDLm2PsOR3xtyFDrEf-XsXLqToZAF5m_rkcvuhNLp5g9qWujhadEz2dGHeiY205JUhwPLdp_hU9kTvJuW8U1U9JVJHqi_
云盘连接:http://pan.baidu.com/s/1kVO9w9p