嗯明天要開始作A組了,由於B組全是原題...題還特別水...ios
T1 題意簡述:jzoj3927算法
解題思路:各位大佬有沒有以爲這道題很眼熟呀?ui
沒錯,這道題和[SDOI2008]儀仗隊如出一轍...spa
作過的大佬能夠跳過了....net
畫圖觀察發現答案即爲sum[phi[1]~phi[n-1]]+2。code
注意當n=1時要特判。blog
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define ll long long using namespace std; ll n,jdg[100001],prime[100001],phi[100001],cnt,ans; void getphi() { phi[1]=1;jdg[1]=1; for(ll i=2;i<=n;i++) { if(!jdg[i]) { prime[++cnt]=i; phi[i]=i-1; } for(ll j=1;j<=cnt;j++) { if(i*prime[j]>n) break; jdg[i*prime[j]]=1; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } int main() { scanf("%lld",&n); if(n==1){printf("0\n");return 0;} getphi(); for(int i=1;i<n;i++) ans+=phi[i]; ans=ans*2+1; printf("%lld\n",ans); }
T2 題意簡述:jzoj3928排序
解題思路:純貪心。隊列
把事件按時間從早到晚排序,用一個小根堆維護。事件
若隊列內元素個數小於當前事件時間,則直接加入隊列。
不然,把隊列中價值最低的元素與當前事件價值對比。
若當前事件價值較大就把堆頂彈出,壓入當前事件。
注意特判價值爲負以及時間爲0的狀況。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> #define ll long long using namespace std; ll n,ans; struct uio{ ll tim,val; }win[200001]; priority_queue<ll,vector<ll>,greater<ll> > que; bool cmp(uio x,uio y) { if(x.tim==y.tim) return x.val>y.val; return x.tim<y.tim; } int main() { scanf("%lld",&n); for(ll i=1;i<=n;i++) scanf("%lld%lld",&win[i].tim,&win[i].val); sort(win+1,win+1+n,cmp); for(ll i=1;i<=n;i++) { if(win[i].val<0||win[i].tim==0) continue; if(que.size()<win[i].tim){que.push(win[i].val);continue;} else if(que.top()<win[i].val){que.pop();que.push(win[i].val);continue;} } while(!que.empty()) { ans+=que.top(); que.pop(); } printf("%lld\n",ans); return 0; }
T3 題意簡述:jzoj3929
解題思路:題解中提供了2種思路。這裏介紹(懶人專屬)貪心作法。
發現題目中給的圖是基環森林(樹),所以能夠貪心。
相似拓撲排序,找出圖中全部入度爲0的點,壓入隊列中。
對於一個點,查詢它和它的兒子是否已經計入答案。若均未計入答案則兒子計入答案。
查詢當前點的兒子的兒子是否入度爲0,如果則壓入隊列。
最後會剩下一個某些點已被染色的環,按照以上策略再次貪心便可。
另外一種作法是dp,想看這種解法的能夠去PoPoQQQ大佬那裏看看。
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<queue> using namespace std; int n,ans,son[1000001],head[1000001],d[1000001],vis[1000001]; queue<int> que; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) {scanf("%d",&son[i]);d[son[i]]++;} for(int i=1;i<=n;i++) if(!d[i]) que.push(i); while(!que.empty()) { int now=que.front();que.pop(); if(!vis[now]&&!vis[son[now]]) { vis[son[now]]=1,ans++; d[son[son[now]]]--; if(!d[son[son[now]]]) que.push(son[son[now]]); } vis[now]=1; } for(int i=1;i<=n;i++) if(!vis[i]) { vis[i]=1; int tmp=son[i],cnt=1; while(tmp!=i) vis[tmp]=1,tmp=son[tmp],cnt++; ans+=cnt/2; } printf("%d\n",ans); return 0; }