題解不按順序給出
目錄:
ycz的妹子
題目背景:
\(ycz\)有很多很多的妹子(\(ycz\):瞎說)
題目描述:
機房神犇\(ycz\)有n個青梅竹馬,她們分別住在1~n號城市中。小時候的她們美麗可愛,但是由於女大十八變,有些妹子的顏值發生了變化,但是十分重感情的\(ycz\)神犇不忍心拋棄她們,於是記錄下來了她們顏值變化的值,我們用\(C\, x\, y\)表示第\(x\)個城市的妹子的顏值下降了\(y\)(\(y\)有可能是負數)。長大之后的\(ycz\)非常有魅力,有許多妹子被\(ycz\)迷得神魂顛倒,我們用\(I\, x\, y\)表示第\(x\)個城市有一個妹子喜歡上了\(ycz\),她的顏值為\(y\)(\(y\)有可能是負數,但是\(ycz\)來者不拒)。但在中途有一些妹子和\(ycz\)吵架了,於是就分手了,我們用\(D\, x\)表示第\(x\)個妹子和\(ycz\)分手了。
最近神犇\(ycz\)要去全國各地找他的妹子們,為了方便計算,我們珂以把\(ycz\)的妹子所在的城市當作是一條直線,並且挨在一起。神犇\(ycz\)由於忙於和他的妹子們聯系此時已經很累了,於是交給你一個這樣的任務:他想知道他在某個時間去找他的所有妹子們珂以獲得多大的愉悅度,這個愉悅度為他找的妹子的顏值數,你要做的就是求出這個愉悅度之和(注意長大后妹子們的顏值可能為負數/滑稽)。
注意:每個城市只允許有一個妹子,也就是說后來喜歡上\(ycz\)的妹子會趕走之前這個城市喜歡\(ycz\)的妹子(一城不容二女)。
輸入格式:
第一行兩個正整數\(n\)和\(m\) \((1<=n<=100000)\)
第二行為\(n\)個整數\(a_i\),表示小時候\(ycz\)的青梅竹馬的顏值\((1<=a_i<=10^9)\)
接下來\(m\)行,每行為一條信息,每條信息可能是下面的一種:
\(C\, x\, y\)表示第\(x\)個城市的妹子的顏值下降了\(y\)
\(I\, x\, y\)表示在第\(x\)個城市有一個顏值為\(y\)的妹子迷上了\(ycz\)
\(D\, x\)表示第\(x\)個妹子和\(ycz\)分手了
\(Q\)表示\(ycz\)現在想知道如果現在去找他所有的妹子們珂以獲得多大的愉悅度
說明:妹子們居住的城市編號最大為\(5\times 10^5\)
輸出格式:
對於每一個\(Q\)輸出一個整數
樣例輸入:
5 10
1 2 3 4 5
Q
C 3 2
Q
I 6 6
Q
D 4
Q
C 4 2
I 7 9
Q
樣例輸出:
15
13
19
15
22
提示與說明:
對於30%的數據\(1<=n,m<=10\)
對於70%的數據\(1<=n,m<=1000\)
對於100%的數據\(1<=n,m<=100000,1<=a_i,y<=10^9\)
題解:
30分:我也不知道怎么拿啊...(暴力分xiajb給的)
70分:直接暴力就好了...
code:點此跳過此代碼
/*Program from Luvwgyx*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100010;
int n,m,a[maxn];char s[10];
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=m;i++){
scanf("%s",s+1);
if(s[1]=='C'){
int x=read(),y=read();
a[x]-=y;
}
if(s[1]=='I'){
int x=read(),y=read();
a[x]=y;
}
if(s[1]=='D'){
int cnt=0,pos,x=read();
for(int i=1;i<=maxn-10;i++)
if(a[i]){cnt++;if(cnt==x){pos=i;break;}}
a[pos]=0;
}
if(s[1]=='Q'){
int ans=0;
for(int i=1;i<=maxn-10;i++)
ans+=a[i];
printf("%d\n",ans);
}
}
return 0;
}
100分:
線段樹中存顏值和以及妹子的數量就好了,具體的代碼去看。
PS:應Wolfycz牆裂要求,此處貼上他的代碼(好丑啊)我代碼在下面,泥萌覺得哪個好看就看哪個吧QAQ
code:點此跳過此代碼
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=1e5;
int val[(N<<1)+10];
struct Segment{
#define ls (p<<1)
#define rs (p<<1|1)
struct node{
int cnt;ll sum;
void insert(int _sum,int _cnt){sum=_sum,cnt=_cnt;}
node(){sum=cnt=0;}
}tree[(N<<3)+10];
friend node operator +(const node &x,const node &y){
node z;
z.sum=x.sum+y.sum;
z.cnt=x.cnt+y.cnt;
return z;
}
void build(int p,int l,int r){
if (l==r){
tree[p].insert(val[l],(bool)val[l]);
return;
}
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
tree[p]=tree[ls]+tree[rs];
}
void change(int p,int l,int r,int x,int v){
if (l==r){
tree[p].insert(v,1);
return;
}
int mid=(l+r)>>1;
if (x<=mid) change(ls,l,mid,x,v);
else change(rs,mid+1,r,x,v);
tree[p]=tree[ls]+tree[rs];
}
void insert(int p,int l,int r,int x,int v){
if (l==r){
tree[p].sum-=v;
return;
}
int mid=(l+r)>>1;
if (x<=mid) insert(ls,l,mid,x,v);
else insert(rs,mid+1,r,x,v);
tree[p]=tree[ls]+tree[rs];
}
void Delete(int p,int l,int r,int x){
if (l==r){
tree[p].insert(0,0);
return;
}
int mid=(l+r)>>1;
if (x<=tree[ls].cnt) Delete(ls,l,mid,x);
else Delete(rs,mid+1,r,x-tree[ls].cnt);
tree[p]=tree[ls]+tree[rs];
}
}Tree;
char s[2];
int main(){
int n=read(),m=read();
for (int i=1;i<=n;i++) val[i]=read();
Tree.build(1,1,N<<1);
for (int i=1;i<=m;i++){
scanf("%s",s);
if (s[0]=='C'){
int x=read(),y=read();
Tree.insert(1,1,N<<1,x,y);
}
if (s[0]=='I'){
int x=read(),y=read();
Tree.change(1,1,N<<1,x,y);
}
if (s[0]=='D'){
int x=read();
Tree.Delete(1,1,N<<1,x);
}
if (s[0]=='Q') printf("%lld\n",Tree.tree[1].sum);
}
return 0;
}
/*Program from Luvwgyx*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn=2e5+10;
ll n,m,a[maxn];char s[10];
struct node{ll cnt,sum;}tree[maxn<<2];
ll read(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void update(ll k){
tree[k].cnt=tree[k<<1].cnt+tree[k<<1|1].cnt;
tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
return;
}
void build(ll k,ll l,ll r){
if(l==r){
tree[k].sum=a[l];
if(a[l]!=0)tree[k].cnt++;
return ;
}
ll mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
update(k);
}
void change(ll k,ll l,ll r,ll x,ll y){
if(l==r){tree[k].sum-=y;/*prllf("\n%d\n",l);*/return ;}
ll mid=(l+r)>>1;
if(x<=mid)change(k<<1,l,mid,x,y);
else change(k<<1|1,mid+1,r,x,y);
update(k);
}
void add(ll k,ll l,ll r,ll x,ll y){
if(l==r){tree[k].sum=y;tree[k].cnt=1;/*prllf("\n%d\n",l);*/return ;}
ll mid=(l+r)>>1;
if(x<=mid)add(k<<1,l,mid,x,y);
else add(k<<1|1,mid+1,r,x,y);
update(k);
}
void del(ll k,ll l,ll r,ll x){
if(l>r)return ;//prllf("%d %d\n",l,r);
if(l==r&&x==tree[k].cnt){tree[k].sum=0;tree[k].cnt--;return ;}
ll mid=(l+r)>>1;//prllf("%d\n",tree[k<<1].cnt);
if(x<=tree[k<<1].cnt)del(k<<1,l,mid,x);
else del(k<<1|1,mid+1,r,x-tree[k<<1].cnt);
update(k);
}
/*
void dfs(ll k,ll l,ll r){
if(l==r){if(tree[k].sum!=0)prllf("%d:%d ",l,tree[k].sum);return ;}
ll mid=(l+r)>>1;
dfs(k<<1,l,mid);dfs(k<<1|1,mid+1,r);
}
*/
int main(){
//freopen("girl10.in","r",stdin);
//freopen("girl10.out","w",stdout);
n=read();m=read();
for(ll i=1;i<=n;i++)a[i]=read();
build(1,1,maxn-10);
while(m--){
scanf("%s",s);
if(s[0]=='C'){ll x=read(),y=read();change(1,1,maxn-10,x,y);}
if(s[0]=='I'){ll x=read(),y=read();add(1,1,maxn-10,x,y);}
if(s[0]=='D'){ll x=read();del(1,1,maxn-10,x);}
if(s[0]=='Q')printf("%lld\n",tree[1].sum);
//dfs(1,1,maxn-10);puts("");
}
return 0;
}
/*
2 11
18 4
C 2 -1
C 1 0
I 19 -17
I 8 -1
D 3
I 19 12
Q
D 1
C 2 -2
D 2
Q
*/
lty loves 96!
題目背景:
眾所周知,\(lty\)非常喜歡\(96\)這兩個數字(想歪的現在馬上面壁去),更甚於復讀(人本復)!
題目描述:
由於愛屋及烏,因此,\(lty\)對於那些含有\(96\)的數也非常喜歡,而這里的含有不是一般的含有,而是具有以下性質的含有(三條都需要滿足):
- 這個數為一個\(N\)位數,且沒有前置零
- 這個數中至少要出現\(M\)次\(9\)和\(6\)(例:\(986996\)中出現了\(5\)次,\(9\)出現了\(3\)次,\(6\)出現了\(2\)次,共計\(5\)次)
- 這個數存在任意連續的三位\(A\),\(B\),\(C\),滿足下面任意一條
- \(A+B+C\)為\(9\)或\(6\)
- \((A^2+B^2)\)%\(C\)為\(9\)或\(6\),如果\(C\)為\(0\),則該條件視為不滿足
輸入格式:
一行,兩個數\(N\),\(M\)。
輸出格式:
一個數,表示這樣的數的個數。
樣例輸入:
3 1
樣例輸出:
452
提示與說明:
對於10%的數據,\(N<=6\),
對於40%的數據,\(N<=18\),
對於100%的數據,\(N<=50\),\(0<=M<=N\)。
題解:
很簡單的一道數位dp。
記錄\(f[i][a][b][j][k](a,b\leq 9;i,j\leq N;k=0\ or\ 1)\),表示一個\(i\)位數,第\(i\)位和第\(i-1\)位分別為\(a,b\),這個數中有\(j\)個6和9,這個數是否出現過題目中描述的兩個條件,有則\(k=1\),沒有則\(k=0\)。
轉移:
當\(a,b,c\)不滿足題目中條件時:
否則
\(f\)數組的類型?
如果你開\(int\)類型,你可以獲得\(10\)分的好成績。
如果你開\(long long\)類型,你可以獲得\(40\)分的好成績。
如果你開普通的未壓位高精度類型,你可以獲得\(0\)分的好成績。
如果你使用任意壓位高精度類型,你可以獲得\(100\)分的好成績。
emmmm,好像有\(dalao\)用\(int128\)水了\(85pts\)來着....
code:點此跳過此代碼
/*Program from wym*/
#include<bits/stdc++.h>
const int maxn=50;
const int digit=9;
const int base=1000000000;
struct bignum{
int v[maxn/digit+2];
int clear(){
memset(v,0,sizeof v);
return 0;
}
int print() {
printf("%d",v[v[0]]);
for(int i=v[0]-1; i>0; --i){
int k=1;
for(int j=1; j<digit; ++j){
k*=10;
if(v[i]<k)putchar('0');
}printf("%d",v[i]);
}
puts("");
return 0;
}
};
bignum operator +(bignum a,bignum b){
bignum ans; ans.clear();
ans.v[0]=std::max(a.v[0],b.v[0]);
int r=0;
for(int i=1; i<=ans.v[0]; ++i){
ans.v[i]=a.v[i]+b.v[i]+r;
r=ans.v[i]/base;
ans.v[i]%=base;
}
if(r!=0)ans.v[++ans.v[0]]=r;
return ans;
}
bignum operator +=(bignum &a,bignum b){
a=a+b;
return a;
}
bignum f[maxn+1][10][10][maxn+1][2],ans;
int n,m;
int main(){
scanf("%d%d",&n,&m);
for(int i=0; i<=n; ++i)
for(int a=0; a<=9; ++a)
for(int b=0; b<=9; ++b)
for(int j=0; j<=n; ++j){
f[i][a][b][j][0].clear();
f[i][a][b][j][1].clear();
}
f[0][0][0][0][0].v[0]=1;
f[0][0][0][0][0].v[1]=1;
for(int i=1; i<=n; ++i)
for(int a=0; a<=9; ++a)
for(int b=0; b<=9; ++b)
for(int j=0; j<=i; ++j)
for(int c=0; c<=9; ++c){
int last_j=j-(((a==6)||(a==9))?1:0);
if((last_j<0)||(last_j>=i))continue;
if((i>=3)&&(((a+b+c==9)||(a+b+c==6))||((c!=0)&&(((a*a+b*b)%c==9)||((a*a+b*b)%c==6)))))
f[i][a][b][j][1]+=f[i-1][b][c][last_j][0]+f[i-1][b][c][last_j][1];
else {
f[i][a][b][j][0]+=f[i-1][b][c][last_j][0];
f[i][a][b][j][1]+=f[i-1][b][c][last_j][1];
}
}
ans.clear();
for(int i=1; i<=9; ++i)
for(int j=0; j<=9; ++j)
for(int k=m; k<=n; ++k)
ans+=f[n][i][j][k][1];
ans.print();
return 0;
}
mzf的考驗
題目背景:
\(mzf\)立志要成為一個豪傑,當然,他也是一個\(OIer\)。
他希望自己除了會\(OI\)之外還會各種東西,比如心理學、吉他、把妹等等。
為了讓自己有更大的魅力,他不駝背,不熬夜,整天鍛煉,雙目炯炯有神,是我們機房最不像\(OIer\)的人。
然而,在與我們格格不入若干天並且將《易經》研究透徹之后,承受不住我們對他另類的言論,他爆發了。
機房在那一剎那仿佛天塌地陷,世界末日。
題目描述:
八卦有乾、坤、震、巽、坎、離、艮、兌;
兩兩組合,一上一下,形成了六十四卦,每卦六爻,一共三百八十四爻。
爻分陰陽,陽爻性屬陽剛,陰爻性屬陰柔。天下之大,無奇不有。千奇百怪,皆出此處。
\(mzf\)研究透徹了易經之后,畫出了\(n\)個奇怪的圖案。他說那是他改進出來的更強大的卜卦體系。
每一個圖案有二十行,每一行要么是陰爻\((0)\),要么是陽爻\((1)\),作為一個\(OIer\),我們可以將卦象看成一個個二進制串;
他將\(n\)個圖案畫在了符紙上,然后進行\(m\)次操作:
操作1:翻轉區間\([l,r]\)的圖案,比如\((3,1,2,5)\)變成\((5,2,1,3)\);
操作2:\(mzf\)畫地為卦,將\([l,r]\)之間的卦象都異或上新畫的那個卦象;
操作3:\(mzf\)會詢問機房里的其他人\([l,r]\)之間卦象代表的二進制數權值和。
如果不能正確回答每個操作\(3\),那么機房風水格局將會改變,我們都將...!
由於\(mzf\)瘋狂之下將我們都捆♂綁♂了起來,所以只能求求你來幫我們解決這個問題。
輸入格式:
第一行兩個正整數:\(n\),\(m\)(\(n\)為序列長度,\(m\)為操作個數)
第二行\(n\)個正整數:\(a[i]\) (用\(10\)進制數表示每個卦象)\((1<=i<=n)\)
接下來\(m\)行:每行首先一個正整數\(opt\)表示操作類型
- \(opt==1\):兩個正整數:\(l\),\(r\)。請翻轉區間\([l,r]\);
- \(opt==2\):三個正整數:\(l\),\(r\),\(d\)。請將區間\([l,r]\)中的所有卦象都異或卦象\(d\)。\((0<=d<=10^5)\)
- \(opt==3\):兩個正整數:\(l\),\(r\)。請查詢區間\([l,r]\)的卦象權值和。
輸出格式:
對於每個 \(opt==3\) 的情況,輸出一行答案。
樣例輸入:
8 9
4 6 2 1 7 9 10 2
1 1 4
3 1 6
2 4 5 2
3 1 6
2 1 5 8
3 1 6
2 5 7 10
3 4 7
3 1 10
樣例輸出:
29
29
69
24
59
提示與說明:
對於20%的數據,\(n<=1000\),\(m<=1000\)
對於另外20%的數據,不存在操作\(1\)
對於另外20%的數據,保證\(n\)為\(2\)的次冪,且在操作\(1\)中,保證\(l=i\times(2^j)+1,r=(i+1)\times(2^j)\),其中\(i\),\(j\)為任意值
對於100%的數據,\(n<=10^5\),\(m<=5\times 10^4\),\(1<=l<=r<=n\),\(0<=d<2^{20}\)
題解:
方法一:
暴力模擬,期望得分:20。
code:點此跳過此代碼
/*Program from Luvwgyx*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=1010;
int n,m,a[maxn],b[maxn];
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=m;i++){
int opt=read(),l=read(),r=read(),d;
if(opt==1){
for(int i=l;i<=r;i++)b[i]=a[i];
for(int i=r;i>=l;i--)a[i]=b[l+r-i];
memset(b,0,sizeof(0));
}else if(opt==2){
d=read();
for(int i=l;i<=r;i++)a[i]^=d;
}else if(opt==3){
ll ret=0;
for(int i=l;i<=r;i++)ret+=a[i];
printf("%lld\n",ret);
}
}
return 0;
}
方法二:
不存在操作1,那我們可以考慮用線段樹來做。
普通的線段樹:期望得分:20。
結合暴力,期望得分:40。
代碼就不放了,自己去寫一寫吧
方法三:
有翻轉操作了,但是這個反轉的區間有限制,我們會發現這個區間其實就是線段樹上的區間的左右端點,我們只需要找到這個區間,然后翻轉就好了。
線段樹+拆位異或...期望得分:40分
結合暴力,期望得分:60分
線段樹內維護權值和以及二進制下數位的值,然后拆位異或,注意一下標記下傳之類的就好了。
都是板子,直接上代碼看吧...
code:點此跳過此代碼
/*Program from lichenxi*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mid ((s[x].l+s[x].r)>>1)
#define size (s[x].r-s[x].l+1)
int n,m,opt,x,y,c[21],ans[21],f[21];
long long d[300001],z,sum,w[21],a[300001];
struct oo{int l,r,rev,t[21],ls,rs;long long _XOR;}s[1200001];
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void gettwo(int *a,long long v)
{
int now=0;
while(v)
{
if(v&1)a[now]=1;
v>>=1;now++;
}
}
void update(int x){for(int i=0;i<20;i++)s[x].t[i]=s[s[x].ls].t[i]+s[s[x].rs].t[i];}
void build(int x,int l,int r)
{
s[x].l=l,s[x].r=r;
if(l==r){gettwo(s[x].t,d[l]);return ;}
s[x].ls=x<<1,s[x].rs=x<<1|1;
build(x<<1,l,mid);build(x<<1|1,mid+1,r);
update(x);
}
void pushrev(int x)
{
int ca=s[s[x].ls].r-s[s[x].ls].l,ka=s[s[x].rs].r-s[s[x].rs].l;
s[s[x].ls].l=s[x].l;s[s[x].ls].r=s[s[x].ls].l+ca;
s[s[x].rs].l=s[s[x].ls].r+1;s[s[x].rs].r=s[s[x].rs].l+ka;
}
void pushdown_rev(int x)
{
s[s[x].ls].rev^=1,s[s[x].rs].rev^=1,s[x].rev^=1;
swap(s[x].ls,s[x].rs);
pushrev(x);
}
void push_XOR(int *c,int x){for(int i=0;i<20;i++)if(c[i])s[x].t[i]=size-s[x].t[i];}
void pushdown_XOR(int x)
{
s[s[x].ls]._XOR^=s[x]._XOR;s[s[x].rs]._XOR^=s[x]._XOR;
for(int i=0;i<20;i++)f[i]=0;gettwo(f,s[x]._XOR);
push_XOR(f,s[x].ls);push_XOR(f,s[x].rs);
s[x]._XOR=0;
}
void putrev(int x,int l,int r)
{
pushrev(x);
if(s[x].rev)pushdown_rev(x);
if(s[x]._XOR)pushdown_XOR(x);
if(s[x].l==l&&s[x].r==r)
{
swap(s[x].ls,s[x].rs);
s[s[x].ls].rev^=1;s[s[x].rs].rev^=1;
int ca=s[s[x].ls].r-s[s[x].ls].l,ka=s[s[x].rs].r-s[s[x].rs].l;
s[s[x].ls].l=s[x].l;s[s[x].ls].r=s[s[x].ls].l+ca;
s[s[x].rs].l=s[s[x].ls].r+1;s[s[x].rs].r=s[s[x].rs].l+ka;
return ;
}
if(l<=mid)putrev(s[x].ls,l,r);
if(r>mid)putrev(s[x].rs,l,r);
update(x);
}
void change(int x,int l,int r,long long d)
{
pushrev(x);
if(s[x].rev)pushdown_rev(x);
if(s[x]._XOR)pushdown_XOR(x);
if(l<=s[x].l&&r>=s[x].r){push_XOR(c,x),s[x]._XOR^=d;return ;}
if(l<=mid)change(s[x].ls,l,r,d);
if(r>mid)change(s[x].rs,l,r,d);
update(x);
}
void get(int x,int l,int r)
{
pushrev(x);
if(s[x].rev)pushdown_rev(x);
if(s[x]._XOR)pushdown_XOR(x);
if(l<=s[x].l&&r>=s[x].r)
{
for(int i=0;i<20;i++)ans[i]+=s[x].t[i];
return ;
}
if(l<=mid)get(s[x].ls,l,r);
if(r>mid)get(s[x].rs,l,r);
update(x);
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
w[0]=1;
for(int i=1;i<22;i++)w[i]=w[i-1]<<1;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%lld",&d[i]);
if(n<=1000&&m<=1000){
while(m--){
int opt=read(),l=read(),r=read(),x;
if(opt==1){
for(int i=l;i<=r;i++)a[i]=d[i];
for(int i=r;i>=l;i--)d[i]=a[l+r-i];
memset(a,0,sizeof(a));
}else if(opt==2){
x=read();
for(int i=l;i<=r;i++)d[i]^=x;
}else if(opt==3){
long long ret=0;
for(int i=l;i<=r;i++)ret+=d[i];
printf("%lld\n",ret);
}
}
return 0;
}
build(1,1,n);
while(m--)
{
scanf("%d%d%d",&opt,&x,&y);
if(opt==1)putrev(1,x,y);
if(opt==2)
{
scanf("%lld",&z);
for(int i=0;i<20;i++)c[i]=0;
gettwo(c,z);change(1,x,y,z);
}
if(opt==3)
{
for(int i=0;i<20;i++)ans[i]=0;get(1,x,y);
sum=0;for(int i=0;i<20;i++)sum+=ans[i]*w[i];
printf("%lld\n",sum);
}
}
}
方法四:
當操作\(1\)沒有限制后,我們可以想到用平衡樹,開\(20\)棵平衡樹就可以\(TLE\)了(常數小的說不定卡的過)。每次翻轉的時候我們需要翻轉\(20\)棵平衡樹,這樣非常不優。那么我們就把每個數的二進制存到平衡樹的節點上,每次異或的時候再拿出來用,翻轉操作也只要做一次就好。理論時間復雜度\(O(20\ m\ logn)\),常數小的基本上可以過
至於有\(dalao\)寫的是\(splay\)卻\(55\)或\(60\)啥的我也不知道啥情況啊....
我真的沒有想卡常啊...可能是我的\(splay\)常數比較小吧...說不定用\(fhq\ treap\)常數小一些,但是我不會寫
期望得分:100分。
code:點此跳過此代碼
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=5e5;
int v[N+10],g[20];
void Extract(int x,int *cnt){for (int i=0;i<20;i++) cnt[i]=x&1,x>>=1;}
struct Splay{
#define ls(x) tree[x][0]
#define rs(x) tree[x][1]
#define T(x) (rs(f[x])==x)
ll sum[N+10];
int tree[N+10][2],f[N+10],size[N+10],cnt[N+10][20],Xor[N+10],val[N+10],A[20];
bool rev[N+10];
int root,len;
void updata(int x){
size[x]=size[ls(x)]+size[rs(x)]+1;
sum[x]=sum[ls(x)]+sum[rs(x)]+val[x];
for (int i=0;i<20;i++) cnt[x][i]=cnt[ls(x)][i]+cnt[rs(x)][i]+((val[x]>>i)&1);
}
void move(int x){
int fa=f[x],son=tree[x][T(x)^1];
tree[x][T(x)^1]=fa;
tree[fa][T(x)]=son;
if (son) f[son]=fa;
f[x]=f[fa];
if (f[x]) tree[f[x]][T(fa)]=x;
f[fa]=x;
updata(fa),updata(x);
}
void splay(int x){
while (f[x]){
if (f[f[x]]) T(f[x])==T(x)?move(f[x]):move(x);
move(x);
}
root=x;
}
void Add_rev(int x){
if (!x) return;
swap(ls(x),rs(x));
rev[x]^=1;
}
void Add_xor(int x,int v){
if (!x) return;
Extract(v,A);
ll res=0;
for (int i=0;i<20;i++){
if (A[i]) cnt[x][i]=size[x]-cnt[x][i];
res+=1ll*cnt[x][i]*g[i];
}
sum[x]=res;
val[x]^=v,Xor[x]^=v;
}
void pushdown(int x){
if (rev[x]){
Add_rev(ls(x));
Add_rev(rs(x));
rev[x]=0;
}
if (Xor[x]){
Add_xor(ls(x),Xor[x]);
Add_xor(rs(x),Xor[x]);
Xor[x]=0;
}
}
int find(int x,int i){
pushdown(i);
if (size[ls(i)]+1==x) return i;
if (x<=size[ls(i)]) return find(x,ls(i));
return find(x-size[ls(i)]-1,rs(i));
}
void reverse(int l,int r){
int x=find(l,root),y=find(r+2,root);
splay(x),splay(y);
if (f[x]!=root) move(x);
Add_rev(rs(x));
// updata(x),updata(y);
}
void _xor(int l,int r,int v){
int x=find(l,root),y=find(r+2,root);
splay(x),splay(y);
if (f[x]!=root) move(x);
Add_xor(rs(x),v);
updata(x),updata(y);
}
ll Query(int l,int r){
int x=find(l,root),y=find(r+2,root);
splay(x),splay(y);
if (f[x]!=root) move(x);
return sum[rs(x)];
}
void build(int fa,int l,int r,int &x){
if (l>r) return;
int mid=(l+r)>>1;
x=++len,f[x]=fa,val[x]=v[mid];
if (l==r){
size[x]=1,sum[x]=val[x];
Extract(val[x],cnt[x]);
return;
}
build(x,l,mid-1,ls(x));
build(x,mid+1,r,rs(x));
updata(x);
}
void init(int n){
len=2,root=1;
rs(1)=size[1]=2,f[2]=size[2]=1;
build(2,1,n,ls(2));
updata(2),updata(1);
}
}Tree;
int main(){
g[0]=1;
for (int i=1;i<20;i++) g[i]=g[i-1]<<1;
int n=read(),m=read();
for (int i=1;i<=n;i++) v[i]=read();
Tree.init(n);
for (int i=1;i<=m;i++){
int type=read(),l=read(),r=read();
if (type==1) Tree.reverse(l,r);
if (type==2) Tree._xor(l,r,read());
if (type==3) printf("%lld\n",Tree.Query(l,r));
}
return 0;
}
hby與tkw的基情
題目背景:
基情恆久遠,一對永流傳。
\(hby\)和\(tkw\)是一對好基友,他們經常在一起做♂游♂戲 (/滑稽)。
題目描述:
他們喜歡玩字符串游戲,尤其喜歡玩回文串。每次\(hby\)會給出一個數\(n\),那么\(tkw\)就需要給出\(Ans=\sum\limits_{i=1}^ni\times s[i]\times[i\%2]\)
其中\(s[i]\)代表長度為\(i\)的數字回文串的個數,最后面是\(bool\)表達式
不過由於\(tkw\)最近學\(ycz\)找妹紙去了,於是他就將這個問題交給了你,如果你不能在\(1s\)內答出來,那么\(hby\)和\(tkw\)的基情將會破裂!(不過那樣tkw就可以安心地找妹紙了)
由於答案會非常大,所以你只需要輸出答案\(\%10^9+7\)的值即可
輸入格式:
第一行一個整數\(T\)。
接下來\(T\)行,每行一個數\(n\)。
輸出格式:
共\(T\)行,每行代表一個答案
樣例輸入:
2
1
3
樣例輸出:
26
2054
提示與說明:
對於10%的數據:\(n<=5\)
對於另外20%的數據:\(\sum n<=10^7\)
對於另外20%的數據:\(T=1\)
對於100%的數據:\(T<=5\times 10^5,n<=10^9\)
題解:
10%:隨便玩玩就好
30%:發現:\(s[i]=s[i-2] * 26\) ,\(s[1]=26\),遞推即可
50%:由於只有一組數據,可以用矩陣快速冪優化以上的遞推。
100%:開了\(O2\)說不定矩陣快速冪就過了。。。
然后我們要求的式子其實是
其中\(m=\frac{n+1}{2}\)
這東西顯然一個差比數列,裂項相減一下
直接快速冪即可
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int p=1e9+7,inv=2.8e8+2,inv2=5.6e8+5;
int mlt(int a,int b){
int res=1;
for (;b;b>>=1,a=1ll*a*a%p) if (b&1) res=1ll*res*a%p;
return res;
}
int main(){
for (int T=read();T;T--){
int n=(read()+1)>>1;
int Ans=(1ll*(26+1ll*(2*n-1)*mlt(26,n+1)%p-2ll*(mlt(26,n+1)-26)%p*inv%p)*inv%p+p)%p;
printf("%d\n",Ans);
}
return 0;
}
抓住czx
題目背景:
蒟蒻\(lty\)出了一道題,但是由於太弱了,所以希望喜歡鴿子的\(czx\)來幫他寫一個\(std\)。由於\(czx\)又放鴿子去了,所以沒有寫\(std\)。蒟蒻\(lty\)覺得受到了學長的鄙視,所以決定去\(czx\)放鴿子的地方找他。
題意簡述:
\(czx\)放鴿子的地方是一個公園,公園珂以看作是由\(n\)個點\(m\)條邊組成的無向圖(保證無自環),\(lty\)將從公園的入口(\(b\)號節點)進去尋找\(czx\),而\(czx\)會在\(a_i\)個單位時間時變化位置到第\(x\)個節點去,在此之前\(lty\)已經知道了\(czx\)的具體位置和接下來他位置的變化方案,蒟蒻\(lty\)現在想知道他至少需要花多少時間找到\(czx\)。
輸入格式:
第一行四個整數\(n\),\(m\),\(b\),\(e\),\(b\)和\(e\)的意義如題面所示。
接下來\(m\)行,每行三個整數\(x,y,z\),表示\(x\)到\(y\)之間有一條長為\(z\)的邊。
第\(m+1\)行一個整數\(T\),表示\(czx\)位置變化的次數。
接下來\(T\)行,每行兩個整數\(a_i\)和\(x\),表示\(czx\)將在第\(a_i\)個單位時間時移動到第\(x\)個點上去。
輸出格式:
一個整數表示最短所需時間。
樣例輸入:
6 9 1 6
1 2 1
1 3 3
1 4 4
2 3 2
3 6 6
4 5 6
2 5 9
3 5 7
5 6 2
3
10 3
8 5
9 2
樣例輸出:
9
樣例解釋:
在開始的時候就直接走到\(2\)號節點,然后等到\(czx\)過來。總花費時間\(9\)個單位時間。
數據范圍:
對於30%的數據,\(n<=100\),\(m<=1000\),\(T<=100\)
對於另外30%的數據,\(T=0\)
對於100%的數據,\(n<=10^5\),\(m<=5\times10^5\),\(T<=10^5\)
數據結果保證在\(int\)范圍內
題解:
關於\(SPFA\):它還活着(本來想卡的。。。)
30%:瞎\(jb\)弄吧,其實我也不知道這個部分分有啥意義。。。
另外30%:單源最短路板子。(其實是數據太大放不上。。。強行減小數據大小)
100%:首先求一遍單源最短路,如果我們出發去找\(czx\),但是半路中\(czx\)就\(TP\)(\(MC\)玩家)走了,那么我們不如最開始就找之后的某個點。這樣就可以找到一個點,在\(czx\)下次\(TP\)前抓住他即可。
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=1e5,M=1e6;
int pre[(M<<1)+10],now[N+10],child[(M<<1)+10],val[(M<<1)+10];
int h[N+10],deep[N+10];
bool vis[N+10];
int n,m,S,tot;
struct S1{
int x,T;
void insert(int _x,int _T){x=_x,T=_T;}
bool operator <(const S1 &a)const{return T<a.T;}
}A[N+10];
void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
void SPFA(int x){
int head=0,tail=1;
memset(deep,63,sizeof(deep));
h[1]=x,vis[x]=1,deep[x]=0;
while (head!=tail){
if (++head>N) head=1;
int Now=h[head];
for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){
if (deep[son]>deep[Now]+val[p]){
deep[son]=deep[Now]+val[p];
if (!vis[son]){
if (++tail>N) tail=1;
vis[h[tail]=son]=1;
}
}
}
vis[Now]=0;
}
}
int main(){
n=read(),m=read(),S=read(),A[0].insert(read(),0);
for (int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
join(x,y,z),join(y,x,z);
}
SPFA(S);
int T=read();
for (int i=1;i<=T;i++){
int x=read(),y=read();
A[i].insert(y,x);
}
A[++T].insert(0,inf);
sort(A,A+1+T);
for (int i=0;i<=T;i++){
if (deep[A[i].x]<A[i+1].T){
printf("%d\n",max(deep[A[i].x],A[i].T));
break;
}
}
return 0;
}