R6饮料AK赛(NOIP模拟赛)/省选专练HDU 5713 K个联通块
生活随笔
收集整理的這篇文章主要介紹了
R6饮料AK赛(NOIP模拟赛)/省选专练HDU 5713 K个联通块
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
我好菜啊100+60+30
滾犢子吧,兩天加起來才410搞個屁我一年前都可以考400
不說了,題畢竟比較難
T1還是水題但是比昨天難
這是一個開絕對值不等式的題。
根據對奇數和偶數的最優根的歸納一定有一個解是在原址上
于是上界OnLogn
水過
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef int INT; #define int long long const int N=2e5+100; inline void read(int &x){x=0;char ch=getchar();int f=1;while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}x*=f; } int sum[N]={}; int a[N]={}; int n; int ans=1e17+7; INT main(){freopen("snake.in","r",stdin);freopen("snake.out","w",stdout);read(n);sum[0]=0;for(int i=1;i<=n;i++){read(a[i]);a[i]=a[i]-i; // sum[i]=sum[i-1]+a[i];}sort(a+1,a+1+n); // for(int i=1;i<=n;i++){ // cout<<a[i]<<" "; // }for(int i=1;i<=n;i++){sum[i]=sum[i-1]+a[i];} // ans=sum[n];for(int i=1;i<=n;i++){int tmp=(sum[n]-sum[i]-a[i]*(n-i))+(a[i]*i-sum[i]); // cout<<i<<" "<<tmp<<'\n';ans=min(ans,tmp);}cout<<ans;return 0; }T2對我這種弱雞來說就有點難度了
這是一個結論題
但是雖然我推出了重要結論但是還是沒有滿分
30分:枚舉三個斷點
重要結論:
枚舉中間部分斷點
左右兩端尋找盡可能差小的答案值
顯然sum的前綴和是單谷函數
你可以三分值或者二分一階導函數
考試60分代碼
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef int INT; #define int long long const int N=2e5+10; inline void read(int &x){x=0;char ch=getchar();int f=1;while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}x*=f; } int a[N]={}; int sum[N]={}; int n; int ans=1e17+9; struct Node{int minsum,maxsum; }; Node getsum(int L,int R){int l=L;int r=R;int ans=1e16+7;Node ret;ret.maxsum=-1;ret.minsum=1e17;for(int i=l;i<r;i++){if(ans>(abs((sum[i]-sum[L-1])-(sum[R]-sum[i])))){ans=abs((sum[i]-sum[L-1])-(sum[R]-sum[i])); // cout<<i<<" "<<(sum[i]-sum[L-1])<<" "<<(sum[R]-sum[i])<<'\n';ret.maxsum=max((sum[i]-sum[L-1]),(sum[R]-sum[i]));ret.minsum=min((sum[i]-sum[L-1]),(sum[R]-sum[i]));}}return ret; } INT main(){freopen("scream.in","r",stdin);freopen("scream.out","w",stdout);read(n);for(int i=1;i<=n;i++){read(a[i]);sum[i]=sum[i-1]+a[i];}if(n<=300){for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){for(int k=j+1;k<n;k++){int maxsum=max(sum[i],max(sum[j]-sum[i],max(sum[k]-sum[j],sum[n]-sum[k])));int minsum=min(sum[i],min(sum[j]-sum[i],min(sum[k]-sum[j],sum[n]-sum[k])));ans=min(ans,maxsum-minsum);}}}cout<<ans;return 0; }else{if(n<=5000){for(int i=3;i<n;i++){Node tmpleft;tmpleft=getsum(1,i-1);Node tmpright;tmpright=getsum(i,n);int maxsum=max(tmpleft.maxsum,tmpright.maxsum);int minsum=min(tmpleft.minsum,tmpright.minsum); // cout<<i<<" "<<maxsum<<" "<<minsum<<'\n';ans=min(ans,maxsum-minsum);}cout<<ans;return 0;}} // cout<<a[n]return 0; }AC代碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef int INT; #define int long long const int N=2e5+10; inline void read(int &x){x=0;char ch=getchar();int f=1;while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}x*=f; } int a[N]={}; int sum[N]={}; int n; int ans=1e17+9; struct Node{int minsum,maxsum; }; Node getsuml(int L,int R){int l=L;int r=R-1;int ans=1e16+7;int s=sum[R]-sum[L-1];Node ret;while(l^r){int mid=(l+r)/2;if(abs(sum[mid]*2-s)<abs(ans*2-s))ans=sum[mid];if(sum[mid]*2<=s)l=mid+1;else r=mid;}if(abs(sum[l]*2-s)<abs(ans*2-s))ans=sum[l];ret.maxsum=max(s-ans,ans);ret.minsum=min(s-ans,ans);return ret; } Node getsumr(int L,int R){int l=L;int r=R-1;int ans=1e16+7;int s=sum[R]-sum[L-1];Node ret;while(l^r){int mid=(l+r)/2;if(abs((sum[n]-sum[mid])*2-s)<abs(ans*2-s))ans=sum[n]-sum[mid];if((sum[n]-sum[mid])*2<=s)r=mid;else l=mid+1;}if(abs((sum[n]-sum[l])*2-s)<abs(ans*2-s))ans=(sum[n]-sum[l]);ret.maxsum=max(s-ans,ans);ret.minsum=min(s-ans,ans);return ret; } INT main(){freopen("scream.in","r",stdin);freopen("scream.out","w",stdout);read(n);for(int i=1;i<=n;i++){read(a[i]);sum[i]=sum[i-1]+a[i];}for(int i=3;i<n;i++){Node tmpleft;tmpleft=getsuml(1,i-1);Node tmpright;tmpright=getsumr(i,n);int maxsum=max(tmpleft.maxsum,tmpright.maxsum);int minsum=min(tmpleft.minsum,tmpright.minsum); // cout<<i<<" "<<maxsum<<" "<<minsum<<'\n';ans=min(ans,maxsum-minsum);}cout<<ans;return 0; }注意此處的二分寫法新穎
實際乘二是指的右邊除二
原理是我判斷其離平均值有多近。
這等價于倆邊之差更接近
T3
HDU5713 K個聯通塊
省選難度狀壓DP
你不能枚舉邊
但是枚舉點的復雜度是可行的
于是思考一:狀壓DP
定義狀態:
dp(i,j)i:當前有i個聯通塊 j:點集狀態為j即一個狀壓狀態0100101010之類的
f(i)i:一個狀壓狀態表示該點集時可以斷掉的邊的種類使這個點集依舊連通
G(i)i:一個狀壓狀態表示一個點集,目的是選擇后斷開(容斥原理)
用全集減補集求出F
考試30分代碼
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int mod=1e9+9; inline void read(int &x){x=0;char ch=getchar();int f=1;while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}x*=f; } const int N=20; struct Front_star{int u,v,nxt,del; }e[N*N]; int cnt=0; int first[N]={}; void add(int u,int v){cnt++;e[cnt].u=u;e[cnt].v=v;e[cnt].nxt=first[u];e[cnt].del=0;first[u]=cnt; } int n,m,k; int ans=0; int fa[15]={}; inline int getfa(int x){if(fa[x]==x)return x;else return fa[x]=getfa(fa[x]); } inline void Union(int x,int y){int dx=getfa(x);int dy=getfa(y);fa[dy]=dx; } int check(){ for(int i=1;i<=n;i++){fa[i]=i;}for(int i=1;i<=cnt;i++){if(!e[i].del)Union(e[i].u,e[i].v);}for(int i=1;i<=n;i++){getfa(i);}sort(fa+1,fa+1+n);int len=unique(fa+1,fa+1+n)-fa-1;if(len==k){ // for(int i=1;i<=cnt;i++){ // cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].del<<'\n'; // } // cout<<"---------"<<'\n';return 1;} // return 1;return 0; } void dfs(int tim){if(tim==cnt+1){ans+=check();ans=ans%mod;return; } // if(tim>cnt)return;e[tim].del=1;dfs(tim+1);e[tim].del=0;dfs(tim+1); } int main(){freopen("sarsae.in","r",stdin);freopen("sarsae.out","w",stdout);read(n);read(m);read(k);for(int i=1;i<=m;i++){int u,v;read(u);read(v);add(u,v);}dfs(1);cout<<ans;return 0; }修改后代碼
dp更新是一個背包原理
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; typedef int INT; #define int long long inline void read(int &x){x=0;char ch=getchar();int f=1;while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}x*=f; } int f2[1000+20]={}; const int mod=1e9+9; void Pre(){f2[0]=1;for(int i=1;i<=1000;i++){f2[i]=f2[i-1]*2%mod;} } const int N=15; int n,m,k; int maxn; int dp[N][1<<N]={}; int f[1<<N]={}; int g[1<<N]={}; int vis[1<<N]={}; int fa[N]={}; inline int lowbit(int x){return x&(-x); } int getfa(int x){if(fa[x]==x)return fa[x];else return fa[x]=getfa(fa[x]); } void Union(int x,int y){int dx=getfa(x);int dy=getfa(y);fa[dx]=dy; } INT main(){ // freopen("sarsae.in","r",stdin);Pre();read(n);read(m);read(k);maxn=(1<<n)-1;for(int i=1;i<=m;i++){int u,v;read(u);read(v);u--;v--;for(int j=0;j<=maxn;j++){if((j&(1<<u))&&(j&(1<<v))){ // cout<<"working";f[j]++;}}Union(u,v);} for(int st=1;st<=maxn;st++){int minP=lowbit(st);int To=-1;int Fail=0;for(int j=0;j<n;j++){if((1<<j)&st){if(To==-1){To=getfa(j); }else{if(To!=getfa(j)){Fail=1;break;}}}}if(Fail)continue;else vis[st]=1;f[st]=f2[f[st]];g[st]=f[st];for(int j=st;j;j=(j-1)&st){if(j==st)continue;if(!vis[j])continue;if(j&minP){f[st]-=f[j]*g[j^st]%mod;f[st]%=mod;}}} // for(int i=1;i<=maxn;i++){ // cout<<f[i]<<" "; // }dp[0][0]=1;for(int i=1;i<=k;i++){for(int st=1;st<=maxn;st++){int p=lowbit(st);for(int sub=st;sub;sub=(sub-1)&st){if(!vis[sub])continue;if(p&sub){dp[i][st]+=dp[i-1][st^sub]*f[sub]%mod;dp[i][st]%=mod; } }}} cout<<(dp[k][maxn]+mod)%mod; }轉載于:https://www.cnblogs.com/Leo-JAM/p/10079218.html
新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的R6饮料AK赛(NOIP模拟赛)/省选专练HDU 5713 K个联通块的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第二周博客:xml
- 下一篇: 记录一下使用vue/vuex+SSR框架