UPD:T4題解來了
UPD2:T4過了 小細節小細節(指調了兩天
UPD3:初中生能去noip啦 而且擦線省一
怎么說呢 這個結果 也就這樣了吧 下次加油
怎么說呢 自己還是不太行 明明有370的傻逼分的但是還是掛掉了 現在就是個省二彩筆
算了 就這樣吧 反正初中也去不了noip
T1
按照題意模擬即可,考場上腦癱了哈哈哈沒有對拍哈哈哈就忘記了模出來可能會有0這回事哈哈哈出題人nmsl
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int norday[12]={31,28,31,30,31,30,31,31,30,31,30,31};
const int runday[12]={31,29,31,30,31,30,31,31,30,31,30,31};
const int year4=366+365+365+365;
const int run4[4]={366,365,365,365};
const int run41[4]={365,365,365,366};
const int year400=146097;
bool pdrun(int y){
if(y<0){
return y%4==-1;
}
else if(y<=1582){
return y%4==0;
}
else {
return ((y%400==0)||(y%4==0&&y%100!=0));
}
}
int ansy,ansm,ansd;
void getdate(int y,int d){
if(pdrun(y)){
int tmp=0;
for(int i=0;i<12;++i){
tmp+=runday[i];
if(tmp>=d){
tmp-=runday[i];
ansd=d-tmp;
ansm=i+1;
return;
}
}
}
else {
int tmp=0;
for(int i=0;i<12;++i){
tmp+=norday[i];
if(tmp>=d){
tmp-=norday[i];
ansd=d-tmp;
ansm=i+1;
return;
}
}
}
}
signed main(){
int Q;
scanf("%lld",&Q);
while(Q--){
int n;
scanf("%lld",&n);
n++;
ansy=-4713;
if(n<365){
getdate(-4713,n);
printf("%lld %lld %lld BC\n",ansd,ansm,abs(ansy));
}
else if(n<=1721424){
ansy+=n/year4*4;
int tmp=n%year4;
//cout<<tmp<<endl;
if(tmp==0)ansy-=4,tmp=year4;
int sb=0;
for(int i=0;i<4;++i){
sb+=run4[i];
if(sb>=tmp){
ansy+=i;
sb-=run4[i];
sb=tmp-sb;
getdate(ansy,sb);
printf("%lld %lld %lld BC\n",ansd,ansm,abs(ansy));
break;
}
}
}
else {
n-=1721424;
ansy=0;
if(n<=577737){
ansy+=n/year4*4;
int tmp=n%year4;
if(tmp==0)ansy-=4,tmp=year4;
int sb=0;
for(int i=0;i<4;++i){
sb+=run41[i];
if(sb>=tmp){
ansy+=i+1;
sb-=run41[i];
sb=tmp-sb;
getdate(ansy,sb);
printf("%lld %lld %lld\n",ansd,ansm,abs(ansy));
break;
}
}
}
else {
n-=577737;
if(n<=78){
n+=287;
getdate(1582,n);
ansy=1582;
printf("%lld %lld %lld\n",ansd,ansm,abs(ansy));
}
else {
n-=78;
ansy=1582;
ansy+=n/year400*400;
int tmp=n%year400;
if(tmp==0)ansy-=400,tmp=year400;
int sb=0;
for(int i=1583;i<=1583+400-1;++i){
sb+=365+(((i%400==0)||(i%4==0&&i%100!=0))?1:0);
if(sb>=tmp){
ansy+=i-1582;
sb-=365+(((i%400==0)||(i%4==0&&i%100!=0))?1:0);
sb=tmp-sb;
getdate(ansy,sb);
printf("%lld %lld %lld\n",ansd,ansm,abs(ansy));
break;
}
}
}
}
}
}
}
/*
8
365
366
1721423
1721424
2299160
2299161
2299238
2299239
*/
T2
顯然不用去管飼料是個啥,只需要判斷某一位能不能用就可以了(qi互不相同),那么最后\(2^{可以用的位數}-已經有的個數\)即可
注意判k=64和n=0
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
int n,m,c,k;
int alla;
bool tag[1000010];
int sum;
signed main(){
scanf("%llu%llu%llu%llu",&n,&m,&c,&k);
for(int i=1;i<=n;++i){
int ai;
scanf("%llu",&ai);
alla|=ai;
}
for(int i=1;i<=m;++i){
int p,q;
scanf("%llu%llu",&p,&q);
if(!((1ull<<p)&alla)){
if(!tag[p])sum++;
tag[p]=true;
}
}
if(k-sum==64){
if(n==0)puts("18446744073709551616");
else printf("%llu\n",(1ull<<63)-n+(1ull<<63));
}
else {
printf("%llu\n",(1ull<<(k-sum))-n);
}
}
T3
考慮倒着處理,那么就可以把原來的函數序列轉換成每個函數分別需要單獨執行的次數,也就是系數(這一步也要拓撲序以得到每個函數會把前面的函數乘上幾倍)
那么每個函數再用拓撲序一個個往下更新,更新到底層的每個加法函數要執行幾次,最后再執行就好了
兩次的圖剛好是反圖
考場上分明都想出來了卻不敢寫...唉
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=998244353;
int n;
int a[1000010];
int m;
struct func{
int type;
int x,v;
}q[1000010];
int tval[1000010];
struct qwq{
int v;
int nxt;
}edge[1000010];
int cnt=-1;
int head[1000010];
struct ed{
int u,v;
}e[1000010];
void add(int u,int v){
edge[++cnt].nxt=head[u];
edge[cnt].v=v;
head[u]=cnt;
}
int ind[1000010];
void topo_solve1(){
queue<int> qu;
for(int i=1;i<=m;++i){
if(!ind[i])qu.push(i);
}
while(!qu.empty()){
int u=qu.front();
qu.pop();
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v;
tval[v]=(tval[v]*tval[u])%mod;
ind[v]--;
if(!ind[v]){
qu.push(v);
}
}
}
}
int tot;
int Q;
int que[1000010];
int allt[1000010];
int rea[1000010];
void topo_solve2(){
queue<int> qu;
for(int i=1;i<=m;++i){
if(!ind[i]){
qu.push(i);
}
rea[i]=allt[i];
}
while(!qu.empty()){
int u=qu.front();
qu.pop();
int nowk=rea[u];
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].v;
rea[v]=(rea[v]+nowk)%mod;
ind[v]--;
if(!ind[v]){
qu.push(v);
}
nowk=(nowk*tval[v])%mod;
}
}
}
signed main(){
memset(head,-1,sizeof(head));
scanf("%lld",&n);
for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
scanf("%lld",&m);
for(int i=1;i<=m;++i){
scanf("%lld",&q[i].type);
if(q[i].type==1){
scanf("%lld%lld",&q[i].x,&q[i].v);
tval[i]=1;
}
else if(q[i].type==2){
scanf("%lld",&q[i].v);
tval[i]=q[i].v;
}
else {
int cj;
scanf("%lld",&cj);
ind[i]=cj;
for(int j=1;j<=cj;++j){
int x;
scanf("%lld",&x);
add(x,i);
e[cnt].v=x,e[cnt].u=i;
}
tval[i]=1;
}
}
topo_solve1();
scanf("%lld",&Q);
for(int i=1;i<=Q;++i)scanf("%lld",&que[i]);
int k=1;
allt[que[Q]]=(allt[que[Q]]+k)%mod;
for(int i=Q-1;i>=1;--i){
k=k*tval[que[i+1]]%mod;
allt[que[i]]=(allt[que[i]]+k)%mod;
}
k=(k*tval[que[1]])%mod;
memset(head,-1,sizeof(head));
memset(edge,0,sizeof(edge));
int tot=cnt;cnt=-1;
memset(ind,0,sizeof(ind));
for(int i=0;i<=tot;++i){
add(e[i].u,e[i].v);
ind[e[i].v]++;
}
topo_solve2();
for(int i=1;i<=n;++i){
a[i]=(a[i]*k)%mod;
}
for(int i=1;i<=m;++i){
if(q[i].type==1){
a[q[i].x]=(a[q[i].x]+(rea[i]*q[i].v)%mod)%mod;
}
}
for(int i=1;i<=n;++i){
printf("%lld ",a[i]);
}
puts("");
}
/*
3
1 2 3
3
1 1 1
2 2
3 2 1 2
2
2 3
*/
T4
我這個做法可能會比較繁瑣 請耐心看完w
首先顯然如果每條蛇都無腦地吃下去的話 每一輪吃的蛇是固定的。
然后考慮得到這個每一輪吃的蛇的序列后怎么求出答案,顯然我們從后往前掃,如果當前操作的吃蛇的蛇在后面會被吃,那么它就會在這一輪停下來,這一輪之后的所有吃的操作都失效,那么只要這樣處理到第一輪,也就是找到最早的可能停下來的那一輪就能得到答案了。
那么考慮怎么得到這個序列。
設當前序列為a1,...,an且有序排列(題目給的肯定是有序的),分兩種情況來討論:
第一種,an-a1>=a1
那么我們可以發現,這一輪吃完后,最大值一定是不升的(an->an-1或an->an-a1),最小值一定是不降的(a1->a2或a1->an-a1),那么下一輪得到的蛇的長度一定會小於等於這一輪的蛇的長度,也就是說當滿足an-a1>=a1時,每一輪的結果都滿足單調性。所以我們可以開兩個隊列,第一個隊列是原本的數組,第二個隊列用於存放每一輪得出的蛇的長度,然后每次從第一個和第二個的隊尾得到最大值,第一個和第二個的隊頭得到最小值,不斷把當前輪的新蛇的長度放到第二個隊列的頭部就可以了。這樣做顯然是O(n)的。
第二種,an-a1<a1
這個時候就不滿足上面的單調性了,我們要考慮新的做法。
先把第一種得到的兩個有序隊列合並為新的數組a1,...,am,並設k是滿足ak=a1的最大值,也就是a1=a2=...=ak。
然后我們考慮一下在ak+1~am還沒有每一條都吃過的時候的每一輪的新蛇的長度(這里只是長度,只有值滿足,並不一定就是那個下標的蛇):
第一輪,am-a1,顯然小於a1;第二輪,am-1-(am-a1)=am-1-am+a1,小於等於a1;第三輪,am-2-am-1+am-a1 ,是小於a1的。
於是我們發現,每一輪的最小值,要么是從a1~ak中沒有吃的最小的蛇中取得,要么就是上一輪得到的那條新蛇。
於是我們用一個指針,指向一下當前輪的最小值應該從上一輪那條新蛇中取,還是從a1~ak中沒有吃的最小的蛇中取,就可以得到最小值了。
我們又發現最大值會分別是am~ak+1,那么我們這里再用一個指針就可以了。
於是這一個部分也O(n)解決了。
接下來,ak+1~am每一條都至少吃過一條蛇了。根據上面的部分,我們現在剩的蛇要么全都是相等的,值都為a1;要么是一堆a1和一個小於a1的值。
對於第一種情況,將會是最大值吃最小值,然后得到0,然后被次大值吃,次大值的值不變,然后次大值吃次小值...如此遞推。
對於第二種情況,要判斷當前最大值吃完最小值后會不會是0,如果是0的話,下一輪吃他后最大值仍然不變;否則,吃他的最大值就會變成最小值。用一個指針判斷一下就可以了。
這樣也是O(n)的。
於是,這題就O(n)解決了。
code:
#include<bits/stdc++.h>
using namespace std;
int n;
int a[2000010];
int cnt;
struct node{
int val;
int num;
};
node tag[2000010];
int head[2],tail[2];
node q[2][2000010];
node minnode(node a,node b){
if(a.val==b.val?a.num>b.num:a.val>b.val)return b;
else return a;
}
node getmin(){
if(head[1]<=tail[1])return minnode(q[0][head[0]],q[1][head[1]]);
return q[0][head[0]];
}
node maxnode(node a,node b){
if(a.val==b.val?a.num>b.num:a.val>b.val)return a;
else return b;
}
node getmax(){
if(head[1]<=tail[1])return maxnode(q[0][tail[0]],q[1][tail[1]]);
return q[0][tail[0]];
}
int tot;
node newa[2000010];
int top;
node sta[2000010];
int lpos,rpos;
int vis[2000010];
void solve(){
memset(q,0,sizeof(q));
for(int i=1;i<=n;++i){
q[0][i].num=i,q[0][i].val=a[i];
}
cnt=0;
memset(tag,0,sizeof(tag));
head[0]=1,tail[0]=n;
head[1]=n+1,tail[1]=n;
node minn=q[0][1],maxn=q[0][n];
while(minn.val*2<=maxn.val&&tail[0]-head[0]+1+tail[1]-head[1]+1>=2){
node newnode;
bool pdmax=maxn.val==q[1][tail[1]].val&&maxn.num==q[1][tail[1]].num,
pdmin=minn.val==q[1][head[1]].val&&minn.num==q[1][head[1]].num;
--tail[pdmax];
++head[pdmin];
newnode.num=maxn.num;
newnode.val=maxn.val-minn.val;
q[1][--head[1]]=newnode;
tag[++cnt].num=minn.num;
tag[cnt].val=maxn.num;
minn=getmin(),maxn=getmax();
}
tot=0;
int i=head[0],j=head[1];
for(;i<=tail[0]&&j<=tail[1];++i){
maxn=maxnode(q[0][i],q[1][j]);
while(maxn.num==q[0][i].num&&maxn.val==q[0][i].val&&j<=tail[1]){
newa[++tot].val=q[1][j].val,newa[tot].num=q[1][j].num;
j++;
maxn=maxnode(q[0][i],q[1][j]);
}
newa[++tot].val=q[0][i].val,newa[tot].num=q[0][i].num;
}
while(i<=tail[0]){
newa[++tot].val=q[0][i].val,newa[tot].num=q[0][i].num;
i++;
}
while(j<=tail[1]){
newa[++tot].val=q[1][j].val,newa[tot].num=q[1][j].num;
j++;
}
int k=1;
while(newa[1].val==newa[k+1].val&&k<tot)k++;
lpos=1,rpos=tot;
int pos=lpos+1;
bool pd=0;
top=0;
for(;rpos>k;--rpos){
node newnode;
if(!pd){
newnode.val=newa[rpos].val-newa[lpos].val;
newnode.num=newa[rpos].num;
tag[++cnt].num=newa[lpos].num;
tag[cnt].val=newa[rpos].num;
bool ck=false;
if(newnode.val<newa[1].val||(newnode.val==newa[pos].val&&newnode.num<newa[pos].num)){
newa[0].val=newnode.val,newa[0].num=newnode.num;
lpos=0;
}
else {
sta[++top].val=newnode.val,sta[top].num=newnode.num;
lpos=pos;
pos=pos+1;
}
if(lpos==k+1){
pd=true;
lpos=top;
}
}
else {
if(lpos){
newnode.val=newa[rpos].val-sta[lpos].val;
newnode.num=newa[rpos].num;
tag[++cnt].num=sta[lpos].num;
tag[cnt].val=newa[rpos].num;
top--;
}
else {
newnode.val=newa[rpos].val-newa[lpos].val;
newnode.num=newa[rpos].num;
tag[++cnt].num=newa[lpos].num;
tag[cnt].val=newa[rpos].num;
}
if(newnode.val<newa[1].val){
newa[0].val=newnode.val,newa[0].num=newnode.num;
lpos=0;
}
else {
sta[++top].val=newnode.val,sta[top].num=newnode.num;
lpos=top;
}
}
}
while(k>=pos)sta[++top]=newa[k],k--;
if(lpos==0)sta[++top]=newa[lpos];
if(top>1){
int newr=1;
while(newr<top){
node maxn=sta[newr],minn=sta[top];
node newnode;
newnode.val=maxn.val-minn.val;
newnode.num=maxn.num;
tag[++cnt].num=minn.num,tag[cnt].val=maxn.num;
top--;
if(maxn.val!=newnode.val){
newr++;
sta[++top]=newnode;
}
}
}
memset(vis,0,sizeof(vis));
int no=n;
for(int i=cnt;i>=1;--i){
++vis[tag[i].num];
if(vis[tag[i].val]){
while(no>i)no--,--vis[tag[no].num];
}
}
printf("%d\n",n-no+1);
}
int main(){
int T;
scanf("%d",&T);
T--;
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
solve();
while(T--){
int m;
scanf("%d",&m);
for(int i=1;i<=m;++i){
int x;
scanf("%d",&x);
scanf("%d",&a[x]);
}
solve();
}
}