ACM-ICPC 2018 徐州賽區網路賽
學長們還是太強了,膜拜,雖然和清華北大那些比不了,但是還是比較強的,畢竟他們只有三個人,寫了7題
下面是學長們的程式碼
A題
After Incident, a feast is usually held in Hakurei Shrine. This time Reimu asked Kokoro to deliver a Nogaku show during the feast. To enjoy the show, every audience has to wear a Nogaku mask, and seat around as a circle.
There are N guests Reimu serves. Kokoro has 2^k2k masks numbered from 0,1,\cdots,0,1,⋯, 2^k - 12k−1, and every guest wears one of the masks. The masks have dark power of Dark Nogaku, and to prevent guests from being hurt by the power, two guests seating aside must ensure that if their masks are numbered ii and jj , then ii XNOR jj must be positive. (two guests can wear the same mask). XNOR means ~(ii^jj) and every number has kk bits. (11 XNOR 1 = 11=1, 00 XNOR 0 = 10=1, 11 XNOR 0 = 00=0)
You may have seen 《A Summer Day's dream》, a doujin Animation of Touhou Project. Things go like the anime, Suika activated her ability, and the feast will loop for infinite times. This really troubles Reimu: to not make her customers feel bored, she must prepare enough numbers of different Nogaku scenes. Reimu find that each time the same guest will seat on the same seat, and She just have to prepare a new scene for a specific mask distribution. Two distribution plans are considered different, if any guest wears different masks.
In order to save faiths for Shrine, Reimu have to calculate that to make guests not bored, how many different Nogaku scenes does Reimu and Kokoro have to prepare. Due to the number may be too large, Reimu only want to get the answer modules 1e9+71e9+7 . Reimu did never attend Terakoya, so she doesn't know how to calculate in module. So Reimu wishes you to help her figure out the answer, and she promises that after you succeed she will give you a balloon as a gift.
就是一道遞推題,但是我就是一直wa,結果學長上來1A
學長的程式碼:
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int maxn=1e6+5;
long long two[maxn];
void init()
{
two[0]=1;
for(int i=1;i<maxn;i++)two[i]=two[i-1]*2%mod;
}
long long ans[maxn];
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
int N,k;
scanf("%d %d",&N,&k);
ans[1]=two[k];
long long tmp1=((two[k]-1)%mod+mod)%mod;
long long tmp2=((two[k]-2)%mod+mod)%mod;
ans[2]=ans[1]*tmp1%mod;
for(int i=3;i<=N;i++)
{
ans[i]=ans[i-2]*tmp1%mod;
long long tmp=((ans[i-1]-ans[1])%mod+mod)%mod;
tmp=tmp*tmp2%mod;
ans[i]=(ans[i]+tmp)%mod;
}
printf("%lld\n",ans[N]);
}
return 0;
}
不是那麼好理解,我感覺我的思路好理解一些
賽後重新寫了一遍,過了
網上有個人和我思路一模一樣,大家聽不懂我講的可以參考別人的
下面我來講一下我的思路:
首先要知道,每一種面罩都只有一種面罩與他互斥,就是同或為0
然後我也是遞推,分三種,good,bad,neutral,三個陣列遞推,
比如說我0開頭,0就是good,與0互斥的就是bad,剩下的就是neutral
我們再畫一下圖,發現之間的關係,就可以遞推了
good由good和neutral產生
所以 good[i] = good[i-1]+neutral[i-1];
bad由bad和neutra產生
所以bad[i] = bad[i-1]+neutral[i-1];
(前兩種都只產生一個)
neutral有點不同
它由good,bad和neutral產生
good產生2^k-2個,bad產生2^k-2個
neutral產生2^k-3個
然後遞推
t1 = 2^k-2;
t2 = 2^k-3;
g[i] = g[i-1]+n[i-1];
n[i] = t1*g[i-1] + t2*n[i-1] + t1*b[i-1];
b[i] = n[i-1]+b[i-1];
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<time.h>
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
using namespace std;
typedef long long ll;
const int maxn =1e6+5;
const ll mod=1000000007;
ll g[maxn],n[maxn],b[maxn];
int main()
{
// freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int nn;
ll k;
int T;
cin>>T;
while(T--)
{
cin>>nn>>k;
ll tt = k;
g[1]=1,b[1]=n[1]=0;
ll r=1;
ll base =2;
while(k)
{
if(k&1)
r=(r*base)%mod;
base =(base*base)%mod;
k = k/2;
}
r = r%mod;
ll t1=(r-2+mod)%mod;
ll t2 =(r-3+mod)%mod;
for(int i=2;i<=nn;i++)
{
g[i] = ( g[i-1]+n[i-1] )%mod;
n[i] =( ( (t1*g[i-1])%mod+(t2*n[i-1])%mod )%mod+(t1*b[i-1])%mod)%mod;
b[i] =( n[i-1]+b[i-1] )%mod;
}
cout<< ( ( (g[nn]+n[nn] ) %mod)*r )%mod<<endl;
}
return 0;
}
/*
10000
5646 2313
6545 56446
21313 45646
1321 4897
3213 6987
31313 1111
54646 666
33333 4444
2222 111
16346 31321
*/
B題屬於博弈的題
In a world where ordinary people cannot reach, a boy named "Koutarou" and a girl named "Sena" are playing a video game. The game system of this video game is quite unique: in the process of playing this game, you need to constantly face the choice, each time you choose the game will provide 1-31−3 options, the player can only choose one of them. Each option has an effect on a "score" parameter in the game. Some options will increase the score, some options will reduce the score, and some options will change the score to a value multiplied by -1−1 .
That is, if there are three options in a selection, the score will be increased by 11, decreased by 11, or multiplied by -1−1. The score before the selection is 88. Then selecting option 11 will make the score become 99, and selecting option 22 will make the score 77 and select option 33 to make the score -8−8. Note that the score has an upper limit of 100100 and a lower limit of -100−100. If the score is 9999 at this time, an option that makes the score +2+2 is selected. After that, the score will change to 100100 and vice versa .
After all the choices have been made, the score will affect the ending of the game. If the score is greater than or equal to a certain value kk, it will enter a good ending; if it is less than or equal to a certain value ll, it will enter the bad ending; if both conditions are not satisfied, it will enter the normal ending. Now, Koutarou and Sena want to play the good endings and the bad endings respectively. They refused to give up each other and finally decided to use the "one person to make a choice" way to play the game, Koutarou first choose. Now assume that they all know the initial score, the impact of each option, and the kk, ll values, and decide to choose in the way that works best for them. (That is, they will try their best to play the ending they want. If it's impossible, they would rather normal ending than the ending their rival wants.)
Koutarou and Sena are playing very happy, but I believe you have seen through the final ending. Now give you the initial score, the kk value, the ll value, and the effect of each option on the score. Can you answer the final ending of the game?
Input
The first line contains four integers n,m,k,ln,m,k,l(1\le n \le 10001≤n≤1000, -100 \le m \le 100−100≤m≤100 , -100 \le l < k \le 100−100≤l<k≤100), represents the number of choices, the initial score, the minimum score required to enter a good ending, and the highest score required to enter a bad ending, respectively.
Each of the next nn lines contains three integers a,b,ca,b,c(a\ge 0a≥0 , b\ge0b≥0 ,c=0c=0 or c=1c=1),indicates the options that appear in this selection,in which a=0a=0 means there is no option to increase the score in this selection, a>0a>0 means there is an option in this selection to increase the score by aa ; b=0b=0 means there is no option to decrease the score in this selection, b>0b>0 means there is an option in this selection to decrease the score by bb; c=0c=0 means there is no option to multiply the score by -1−1 in this selection , c=1c=1 means there is exactly an option in this selection to multiply the score by -1−1. It is guaranteed that a,b,ca,b,c are not equal to 00 at the same time.
學長們用dp寫的,然而我把這個當成極大極小搜尋了,結果一直超時
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005;
struct node
{
int a,b,c;
node(int a,int b,int c):a(a),b(b),c(c) {}
node() {}
} nodes[maxn];
int dp[maxn][300];
int offset=150;
int n,m,k,l;
int dfs(int d,int s)
{
if(dp[d][s]!=-1)return dp[d][s];
int a=nodes[d].a,b=nodes[d].b,c=nodes[d].c;
if(d==n+1)
{
if(s>=k)return 1;
else if(s<=l)return 0;
return 2;
}
int flag=0;
if(d%2)
{
if(a!=0)
{
int nxts=min(100+offset,s+a);
int tmp=dfs(d+1,nxts);
if(tmp==1)
return dp[d][s]=1;
if(tmp==2)
flag=1;
}
if(b!=0)
{
int nxts=max(-100+offset,s-b);
int tmp=dfs(d+1,nxts);
if(tmp==1)
return dp[d][s]=1;
if(tmp==2)
flag=1;
}
if(c!=0)
{
int nxts=2*offset-s;
int tmp=dfs(d+1,nxts);
if(tmp==1)
return dp[d][s]=1;
if(tmp==2)
flag=1;
}
if(flag)
return dp[d][s]=2;
return dp[d][s]=0;
}
else
{
if(a!=0)
{
int nxts=min(100+offset,s+a);
int tmp=dfs(d+1,nxts);
if(tmp==0)
return dp[d][s]=0;
if(tmp==2)
flag=1;
}
if(b!=0)
{
int nxts=max(-100+offset,s-b);
int tmp=dfs(d+1,nxts);
if(tmp==0)
return dp[d][s]=0;
if(tmp==2)
flag=1;
}
if(c!=0)
{
int nxts=2*offset-s;
int tmp=dfs(d+1,nxts);
if(tmp==0)
return dp[d][s]=0;
if(tmp==2)
flag=1;
}
if(flag)
return dp[d][s]=2;
return dp[d][s]=1;
}
}
int main()
{
memset(dp,-1,sizeof(dp));
scanf("%d %d %d %d",&n,&m,&k,&l);
k+=offset;
l+=offset;
int a,b,c;
for(int i=1; i<=n; i++)
{
scanf("%d %d %d",&a,&b,&c);
nodes[i]=node(a,b,c);
}
int tmp=dfs(1,offset+m);
if(tmp==1)
puts("Good Ending");
else if(tmp==0)
puts("Bad Ending");
else puts("Normal Ending");
}
後來我用記憶化搜尋寫的,就過了,發現好簡單,怎麼搞的
我的程式碼還是比較簡單的
dp[i][j]存值,i表示到達這一層的分數,j表示層數,一共是1--n層,每一層有三種狀態。
現在怎麼覺得這道題有點簡單啊
下面是我的程式碼:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
typedef long long ll;
using namespace std;
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = l ; k <= r ; k++ )
#define mem(a,val) memset(a,val,sizeof a)
#define inf 0x3f3f3f3f
const int maxn = 1e3+4;
int n,first_score,up,down;
int dp[214][maxn];
struct spe
{
int a,b,c;
};
spe p[maxn];
void change( int &x )
{
if( x > 100 )
x = 100;
if( x < -100 )
x = -100;
}
int f( int a,int b,int i )
{
if( i&1 )
return max(a,b);
else return min(a,b);
}
int dfs( int cnt,int score )
{
change(score);
if( cnt == n+1 )
return score;
if( dp[score+100][cnt] != inf )
return dp[score+100][cnt];
int ans = inf;
if( cnt&1 )
ans = -ans;
if( p[cnt].a > 0 )
{
ans = f(ans,dfs(cnt+1,score+p[cnt].a ),cnt);
change(ans);
}
if( p[cnt].b > 0 )
{
ans = f(ans,dfs(cnt+1,score-p[cnt].b ),cnt );
change(ans);
}
if( p[cnt].c > 0 )
{
ans = f(ans,dfs(cnt+1,-score),cnt );
change(ans);
}
dp[score+100][cnt] = ans;
return ans;
}
int main()
{
while( scanf("%d %d %d %d",&n,&first_score,&up,&down) == 4 )
{
mem(dp,inf);
fori(1,n)
scanf("%d %d %d",&p[i].a,&p[i].b,&p[i].c);
int t = dfs(1,first_score);
//cout<<t<<endl;
if( t >= up )
puts("Good Ending");
else if( t <= down )
puts("Bad Ending");
else puts("Normal Ending");
}
return 0;
}
/*
*/
C題是個求期望的題,但是學長他們沒做,可能是時間不夠,但是我們隊看了,不過樣例都湊不出來,後來補了上來,是一道模擬題,其實感覺還比較好寫吧,就是題目超級難理解,還有坑爹的問答區,我真想不通這個*和#跟買彩票前幾位知道有什麼關係
先說一下樣例二吧
4313.16666667 = ( 10000+10000+ 3600+119 + 1080+1080 )/6
就是分別列舉*號,這個還好,但是對於#的處理是:
它只能選一行或一列或斜著的,所以只能對一行一列的值進行累加了比較,由於有多種情況,所以多種情況累加到相應的行或列
,重要的就是累加,累加出來的最大的,就是要選的那一行或那一列
所以我們要分別列舉*和#,注意,*和#的處理方法是不一樣的,而且是先列舉#,後列舉#
Morgana is playing a game called cacti lottery. In this game, morgana has a 3 \times 33×3 grid graph, and the graph is filled with 11 ~ 99 , each number appears only once. The game is interesting, he doesn't know some numbers, but there are also some numbers he knows but don't want to tell you.
Now he should choose three grids, these three grids should be in the same column or in the same row or in the diagonal line. Only after this choice, can he know all numbers in the grid graph. Then he sums the three numbers in the grids he chooses, get the reward as follows:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define mem(a,val) memset(a,val,sizeof a)
#define inf 0x3f3f3f3f
using namespace std;
char s[8][8];
int counter[14];
int cnt;
int remain[15];
bool vis[15];
int starnum,num;
vector<int> star;
vector<int> rest;
double fac[14];
double val[15];
double ans;
double value[100];
void calculate( int m[5][5] )
{
int pos = 0;
fori(1,3)
forj(1,3)
if( s[i][j] == '#' )
m[i][j] = rest[pos++];
fori(1,3)
val[i] += value[ m[i][1]+m[i][2]+m[i][3] ];
fori(4,6)
val[i] += value[ m[1][i-3]+m[2][i-3]+m[3][i-3] ];
val[7] += value[ m[1][1]+m[2][2]+m[3][3] ];
val[8] += value[ m[3][1]+m[2][2]+m[1][3] ];
}
void fill_rest( int time,int m[5][5] )
{
if( time == num )
{
calculate(m);
return;
}
for( int i = 1 ; i < cnt ; i++ )
{
if( !vis[i] )
{
vis[i] = true;
rest.push_back(remain[i]);
fill_rest(time+1,m);
rest.pop_back();
vis[i] = false;
}
}
}
double getval( )
{
int m[5][5];
int pos = 0;
fori(1,3)
forj(1,3)
if( s[i][j] == '*' )
m[i][j] = star[pos++];
else if( s[i][j] != '#' )
m[i][j] = s[i][j]-'0';
mem(val,0);
fill_rest(0,m);
double ma = 0;
fori(1,8)
ma = max(ma,val[i]);
return ma/fac[num];
}
void fill_star( int time )
{
if( time == starnum )
{
ans += getval();
return;
}
for( int i = 1 ; i < cnt ; i++ )
{
if( !vis[i] )
{
vis[i] = true;
star.push_back(remain[i]);
fill_star(time+1);
star.pop_back();
vis[i] = false;
}
}
}
void init()
{
value[6]=10000;
value[7]=36;
value[8]=720;
value[9]=360;
value[10]=80;
value[11]=252;
value[12]=108;
value[13]=72;
value[14]=54;
value[15]=180;
value[16]=72;
value[17]=180;
value[18]=119;
value[19]=36;
value[20]=360;
value[21]=1080;
value[22]=144;
value[23]=1800;
value[24]=3600;
fac[1] = fac[0] = 1;
for( int i = 2 ; i <= 9 ; i++ )
{
fac[i] = fac[i-1]*(double)i;
}
}
int main()
{
init();
int T;
scanf("%d",&T);
while( T-- )
{
cnt = 1;
mem(counter,0);
mem(vis,false);
star.clear();
rest.clear();
starnum = 0;
num = 0;
ans = 0;
fori(1,3)
{
scanf("%s",s[i]+1);
forj(1,3)
{
int t = s[i][j]-'0';
if( t >= 1 && t <= 9 )
counter[t]++;
else if( s[i][j] == '*' )
starnum++;
else if( s[i][j] == '#' )
num++;
}
}
fori(1,9)
if( counter[i] == 0 )
remain[cnt++] = i;
fill_star(0);
cnt--;
double temp = 1;
for( int i = cnt ; i >= cnt-starnum+1 ; i-- )
temp = temp*(double)i;
ans = ans/temp;
printf("%.8f\n",ans);
}
return 0;
}
/*
5
###
###
###
***
***
***
134
***
***
542
***
***
1**
**4
***
*/
F題
Morgana is learning computer vision, and he likes cats, too. One day he wants to find the cat movement from a cat video. To do this, he extracts cat features in each frame. A cat feature is a two-dimension vector <xx, yy>. If x_ixi= x_jxj and y_iyi = y_jyj, then <x_ixi, y_iyi> <x_jxj, y_jyj> are same features.
So if cat features are moving, we can think the cat is moving. If feature <aa, bb> is appeared in continuous frames, it will form features movement. For example, feature <aa , bb > is appeared in frame 2,3,4,7,82,3,4,7,8, then it forms two features movement 2-3-42−3−4 and 7-87−8 .
Now given the features in each frames, the number of features may be different, Morgana wants to find the longest features movement.
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
typedef pair<int,int>pii;
map<pii,int>M[2];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
M[0].clear();
M[1].clear();
int N;
scanf("%d",&N);
int now=0;
int ans=1;
for(int i=1;i<=N;i++)
{
M[now].clear();
int k;
scanf("%d",&k);
int a,b;
for(int j=1;j<=k;j++)
{
scanf("%d %d",&a,&b);
pii tmp=pii(a,b);
if(M[now^1].count(tmp))
{
M[now][tmp]=M[now^1][tmp]+1;
ans=max(ans,M[now][tmp]);
}
else
{
M[now][tmp]=1;
}
}
now^=1;
}
printf("%d\n",ans);
}
return 0;
}
G題
G題是一道思維題,學長的程式碼短的很
There's a beach in the first quadrant. And from time to time, there are sea waves. A wave ( xx , yy ) means the wave is a rectangle whose vertexes are ( 00 , 00 ), ( xx , 00 ), ( 00 , yy ), ( xx , yy ). Every time the wave will wash out the trace of former wave in its range and remain its own trace of ( xx , 00 ) -> ( xx , yy ) and ( 00 , yy ) -> ( xx , yy ). Now the toad on the coast wants to know the total length of trace on the coast after n waves. It's guaranteed that a wave will not cover the other completely.
Input
The first line is the number of waves n(n \le 50000)n(n≤50000).
The next nn lines,each contains two numbers xx yy ,( 0 < x0<x , y \le 10000000y≤10000000 ),the ii-th line means the ii-th second there comes a wave of ( xx , yy ), it's guaranteed that when 1 \le i1≤i , j \le nj≤n ,x_i \le x_jxi≤xj and y_i \le y_jyi≤yj don't set up at the same time.
Output
An Integer stands for the answer.
Hint:
As for the sample input, the answer is 3+3+1+1+1+1=103+3+1+1+1+1=10
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+5;
int x[maxn],y[maxn];
set<int>S;
int n;
long long solve(int *num)
{
long long res=0;
S.clear();
S.insert(0);
for(int i=n;i>=1;i--)
{
int thenum=num[i];
if(S.empty())
{
res+=thenum;
S.insert(thenum);
continue;
}
auto it=S.upper_bound(thenum);
it--;
res+=thenum-(*it);
S.insert(thenum);
}
return res;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d %d",&x[i],&y[i]);
long long ans=solve(x);
ans+=solve(y);
printf("%lld\n",ans);
}
而我是用線段樹寫的,感覺就是麻煩一點,不過也是過了,雖然是賽後過的
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<cmath>
#include<time.h>
#include<map>
typedef long long ll;
using namespace std;
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = l ; k <= r ; k++ )
#define mem(a,val) memset(a,val,sizeof a)
#define inf 0x3f3f3f3f
#define lef rt<<1
#define rig rt<<1|1
#define mid (l+r)>>1
const int maxn = 5e5+5; //老老實實開5e4+5 的陣列runtime_error 可能資料有問題
int cpyx[maxn],cpyy[maxn];
struct spe
{
ll x,y;
};
spe p[maxn];
int n;
ll tree1[maxn<<2],tree2[maxn<<2];
int L,R;
ll query_max( int l,int r,int rt,ll tree[] )
{
if( l >= L && r <= R )
return tree[rt];
int m = mid;
ll ans = 0;
if( m >= L )
ans = max(ans,query_max(l,m,lef,tree) );
if( m < R )
ans = max(ans,query_max(m+1,r,rig,tree) );
return ans;
}
void update_point( int l,int r,int rt,int pos,ll val,ll tree[] )
{
if( l == r )
{
tree[rt] = val;
return;
}
int m = mid;
if( m >= pos )
update_point(l,m,lef,pos,val,tree);
else update_point(m+1,r,rig,pos,val,tree);
tree[rt] = max(tree[lef],tree[rig]);
}
int main()
{
while( scanf("%d",&n) == 1 )
{
mem(tree1,0);
mem(tree2,0);
int cnt = 1,xnum,ynum;
fori(1,n)
{
scanf("%lld %lld",&p[i].x,&p[i].y);
cpyx[cnt++] = p[i].x;
cpyy[cnt++] = p[i].y;
}
sort(cpyx+1,cpyx+cnt);
sort(cpyy+1,cpyy+cnt);
xnum = unique(cpyx+1,cpyx+cnt)-cpyx-1;
ynum = unique(cpyy+1,cpyy+cnt)-cpyy-1;
int x,y;
ll ans = 0;
for( int i = n ; i >= 1 ; i-- )
{
x = lower_bound(cpyx+1,cpyx+xnum+1,p[i].x)-cpyx;
L = x,R = xnum;
ll ma = query_max(1,xnum,1,tree1);
if( p[i].y > ma )
ans += p[i].y-ma;
update_point(1,xnum,1,x,p[i].y,tree1);
//cout<<" after "<<ans<<endl;
y = lower_bound(cpyy+1,cpyy+ynum+1,p[i].y)-cpyy;
L = y,R = ynum;
ma = query_max(1,ynum,1,tree2);
if( p[i].x > ma )
ans += p[i].x-ma;
update_point(1,ynum,1,y,p[i].x,tree2);
//cout<<" after "<<ans<<endl;
//
}
printf("%lld\n",ans);
}
return 0;
}
/*
6
3 3333
21654 54131
5413213 56464
1313 654654
5564 6543
4894 21313
*/
H題是線段樹,其實也可以用樹狀陣列
就是普通的點更新和區間求和,建兩顆樹,一顆乘以權值,另一顆不乘,兩顆同時更新,求和的時候減一個東西就行了
Ryuji is not a good student, and he doesn't want to study. But there are n books he should learn, each book has its knowledge a[i]a[i].
Unfortunately, the longer he learns, the fewer he gets.
That means, if he reads books from ll to rr, he will get a[l] \times L + a[l+1] \times (L-1) + \cdots + a[r-1] \times 2 + a[r]a[l]×L+a[l+1]×(L−1)+⋯+a[r−1]×2+a[r] (LL is the length of [ ll, rr ] that equals to r - l + 1r−l+1).
Now Ryuji has qq questions, you should answer him:
11. If the question type is 11, you should answer how much knowledge he will get after he reads books [ ll, rr ].
22. If the question type is 22, Ryuji will change the ith book's knowledge to a new value.
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
#define lowbit(x) x&-x
long long sum1[maxn],sum2[maxn];
void add(long long *sum,int x,long long val)
{
while(x<maxn)
{
sum[x]+=val;
x+=lowbit(x);
}
}
long long query(long long *sum,int x)
{
long long res=0;
while(x)
{
res+=sum[x];
x-=lowbit(x);
}
return res;
}
long long a[maxn];
int n,q;
long long ask(int l,int r)
{
int len=r-l+1;
long long res=0;
long long tmp=query(sum1,r)-query(sum1,l-1);
long long tmp2;
tmp=tmp*len;
res+=tmp;
tmp=query(sum2,r)-query(sum2,l);
tmp2=query(sum1,r)-query(sum1,l);
tmp=tmp-tmp2*l;
res-=tmp;
return res;
}
void change(int x,long long val)
{
add(sum1,x,val-a[x]);
add(sum2,x,(val-a[x])*x);
a[x]=val;
}
int main()
{
scanf("%d %d",&n,&q);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
add(sum1,i,a[i]);
add(sum2,i,a[i]*i);
}
int x,y,z;
while(q--)
{
scanf("%d %d %d",&x,&y,&z);
if(x==1)
{
printf("%lld\n",ask(y,z));
}
else
{
change(y,z);
}
}
return 0;
}
I題簽到題
Mur loves hash algorithm, and he sometimes encrypt another one's name, and call him with that encrypted value. For instance, he calls Kimura KMR, and calls Suzuki YJSNPI. One day he read a book about SHA-256256 , which can transit a string into just 256256 bits. Mur thought that is really cool, and he came up with a new algorithm to do the similar work. The algorithm works this way: first we choose a single letter L as the seed, and for the input(you can regard the input as a string ss, s[i]s[i] represents the iith character in the string) we calculates the value(|(int) L - s[i]|∣(int)L−s[i]∣), and write down the number(keeping leading zero. The length of each answer equals to 22because the string only contains letters and numbers). Numbers writes from left to right, finally transfer all digits into a single integer(without leading zero(ss)). For instance, if we choose 'z' as the seed, the string "oMl" becomes "1111 4545 1414".
It's easy to find out that the algorithm cannot transfer any input string into the same length. Though in despair, Mur still wants to know the length of the answer the algorithm produces. Due to the silliness of Mur, he can even not figure out this, so you are assigned with the work to calculate the answer.
Input
First line a integer TT , the number of test cases (T \le 10)(T≤10).
For each test case:
First line contains a integer NN and a character zz, (N \le 1000000)(N≤1000000).
Second line contains a string with length NN . Problem makes sure that all characters referred in the problem are only letters.
Output
A single number which gives the answer.
樣例輸入複製
2
3 z
oMl
6 Y
YJSNPI
樣例輸出複製
6
10
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
char s[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int N;
char z[3];
scanf("%d %s",&N,z);
scanf("%s",s);
int ans=0,flag=0;
for(int i=0;i<N;i++)
{
int num=z[0]-s[i];
if(flag)ans+=2;
else if(!flag&&num)
{
flag=1;
if(num<10)ans++;
else ans+=2;
}
}
if(ans==0)ans=1;
printf("%d\n",ans);
}
return 0;
}
J題
After the long vacation, the maze designer master has to do his job. A tour company gives him a map which is a rectangle. The map consists of N \times MN×M little squares. That is to say, the height of the rectangle is NN and the width of the rectangle is MM. The master knows exactly how the maze is going to use. The tour company will put a couple in two different squares in the maze and make them seek each other. Of course,the master will not make them find each other easily. The only thing the master does is building some wall between some little squares. He knows in that way, wherever the couple is put, there is only one path between them. It is not a difficult thing for him, but he is a considerate man. He also knows that the cost of building every wall between two adjacent squares is different(Nobody knows the reason). As a result, he designs the maze to make the tour company spend the least money to build it.
Now, here's your part. The tour company knows you're the apprentice of the master, so they give you a task. you're given QQ qustions which contain the information of where the couple will be put. You need to figure out the length of the shortest path between them.
However,the master doesn't tell you how he designs the maze, but he believes that you, the best student of himself, know the way. So he goes on vacation again.
#include<bits/stdc++.h>
using namespace std;
#define time te
const int maxn = 250000+100;
const int maxm = maxn*4;
typedef pair<int,int> pii;
vector<pii >V[maxn];
struct Edge
{
int from, to, dist;
Edge(int _f,int _t,int _d):from(_f),to(_t),dist(_d){}
Edge(){}
}edges[maxm];
int tot;
void addedge(int u, int v, int dist)
{
edges[tot++] = Edge(u, v, dist);
}
int f[maxn], e[maxm];
bool cmp(int a, int b)
{
return edges[a].dist < edges[b].dist;
}
int find(int a) { return a == f[a] ? a : f[a] = find(f[a]); }
int kruskal(int n)
{
for (int i = 0;i < n;i++)f[i] = i;
for (int i = 0;i < tot;i++)e[i] = i;
sort(e, e + tot, cmp);
int num = 0;
long long ans = 0;
for (int i = 0;i < tot;i++)
{
if (num == n - 1)break;
int u = edges[e[i]].from, v = edges[e[i]].to, dis = edges[e[i]].dist;
int rootu = find(u), rootv = find(v);
if (rootu != rootv) { f[rootu] = rootv; ans += dis; num++; V[u].push_back(pii(v,1));V[v].push_back(pii(u,1));}
else continue;
}
if(num<n-1)return -1;
return ans;
}
//
long long d[maxn];
int dp[maxn][20];
int dep[maxn];
int l[maxn],r[maxn];
int time;
void dfs(int u,int pre,long long dis)
{
d[u]=dis;
dp[u][0]=pre;
++time;
l[u]=time;
for(int i=0;i<V[u].size();i++)
{
pii x=V[u][i];
int v=x.first,w=x.second;
if(v==pre)continue;
dep[v]=dep[u]+1;
dfs(v,u,dis+w);
}
r[u]=time;
}
void rmq(int n)
{
for(int i=1;i<20;i++)
for(int j=0;j<n;j++)
{
if((1<<i)>dep[j])continue;
int k=dp[j][i-1];dp[j][i]=dp[k][i-1];
}
}
int query(int x,int y)
{
if(dep[x]>dep[y])swap(x,y);
for(int j=19;j>=0&&dep[x]!=dep[y];j--)
{
if(dep[y]-(1<<j)<dep[x])continue;
y=dp[y][j];
}
if(x==y)return x;
for(int j=19;j>=0;j--)
{
if(dep[x]-(1<<j)<0||dp[x][j]==dp[y][j])continue;
x=dp[x][j],y=dp[y][j];
}
return dp[x][0];
}
long long getdis(int u,int v)
{
long long res=0;
int lca=query(u,v);
res+=d[u];
res+=d[v];
res-=2LL*(d[lca]);
return res;
}
int main()
{
int N,M;
scanf("%d %d",&N,&M);
char s[3];
int num;
for(int i=0;i<N*M;i++)
{
int nowx=i/M;
int nowy=i%M;
for(int j=1;j<=2;j++)
{
scanf("%s %d",s,&num);
if(s[0]=='X')continue;
if(s[0]=='D')
{
int nxtx=nowx+1;
int nxty=nowy;
int thenum=nxtx*M+nxty;
addedge(i,thenum,-num);
addedge(thenum,i,-num);
}
else
{
int nxtx=nowx;
int nxty=nowy+1;
int thenum=nxtx*M+nxty;
addedge(i,thenum,-num);
addedge(thenum,i,-num);
}
}
}
kruskal(N*M);
dfs(0,-1,0);
rmq(N*M);
int Q;
scanf("%d",&Q);
int x1,y1,x2,y2;
while(Q--)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
x1--,y1--,x2--,y2--;
int u=x1*M+y1;
int v=x2*M+y2;
printf("%lld\n",getdis(u,v));
}
return 0;
}