A:化成x-√n=y+z-√4yz的形式,則顯然n是徹底平方數時有無數組解,不然要求n=4yz,暴力枚舉n的因數便可。注意判斷根號下是否不小於0。html
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define P 1000000007 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } signed main() { int T=read(); while (T--) { int n=read(); int w=sqrt(n); if (w*w==n||(w+1)*(w+1)==n||(w-1)*(w-1)==n) cout<<"infty"<<endl; else { if (n%4) cout<<0<<' '<<0<<endl; else { n/=4; int cnt=0,ans=0; for (int i=1;i*i<=n;i++) if (n%i==0) { if (i+n/i>w) cnt++,ans=(ans+1ll*n*(i+n/i))%P; } cout<<cnt<<' '<<ans<<endl; } } } return 0; //NOTICE LONG LONG!!!!! }
B:f[i][j][k]表示第i步後左邊有j個已訪問城市右邊有k個已訪問城市的機率,轉移顯然。雖然是在一個環上,但不當作環也沒有問題,最後對n取min便可。ios
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define P 1000000007 #define N 510 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int T,f[N][N][N]; int ksm(int a,int k) { int s=1; for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P; return s; } signed main() { T=read(); while (T--) { int n=read(),m=read(),k=read(),p=read(),q=read(); for (int i=1;i<=m;i++) for (int j=0;j<i;j++) for (int k=0;k<i;k++) f[i][j][k]=0; f[1][0][0]=1; for (int i=1;i<m;i++) for (int x=0;x<i;x++) for (int y=0;y<i;y++) f[i+1][max(x-1,0)][y+1]=(f[i+1][max(x-1,0)][y+1]+1ll*p*f[i][x][y])%P, f[i+1][x+1][max(y-1,0)]=(f[i+1][x+1][max(y-1,0)]+1ll*q*f[i][x][y])%P, f[i+1][x][y]=(f[i+1][x][y]+1ll*(100-p-q)*f[i][x][y])%P; int ans=0; for (int x=0;x<m;x++) for (int y=0;y<m;y++) ans=(ans+1ll*f[m][x][y]*ksm(min(x+y+1,n),k))%P; cout<<ans<<endl; } return 0; //NOTICE LONG LONG!!!!! }
C:容易發現至關於要求兩點間存在至少兩條邊不重複路徑,也即兩點在同一邊雙內,用LCT維護邊雙便可。具體見https://www.cnblogs.com/Gloid/p/10056499.html。數組
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 1000010 #define lson tree[k].ch[0] #define rson tree[k].ch[1] #define lself tree[tree[k].fa].ch[0] #define rself tree[tree[k].fa].ch[1] char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,q,fa[N],fa2[N],size[N]; ll ans; struct data{int ch[2],fa,rev; }tree[N]; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} int find2(int x){return fa2[x]==x?x:fa2[x]=find2(fa2[x]);} void rev(int k){if (k) swap(lson,rson),tree[k].rev^=1;} void down(int k){if (tree[k].rev) rev(lson),rev(rson),tree[k].rev=0;} int whichson(int k){return rself==k;} bool isroot(int k){return lself!=k&&rself!=k;} void push(int k){if (!isroot(k)) push(tree[k].fa);down(k);} void move(int k) { int fa=tree[k].fa,gf=tree[fa].fa,p=whichson(k); if (!isroot(fa)) tree[gf].ch[whichson(fa)]=k;tree[k].fa=gf; tree[fa].ch[p]=tree[k].ch[!p],tree[tree[k].ch[!p]].fa=fa; tree[k].ch[!p]=fa,tree[fa].fa=k; } void splay(int k) { push(k); while (!isroot(k)) { int fa=tree[k].fa; if (!isroot(fa)) if (whichson(fa)^whichson(k)) move(k); else move(fa); move(k); } } void access(int k){for (int t=0;k;t=k,k=tree[k].fa=find(tree[k].fa)) splay(k),tree[k].ch[1]=t;} void makeroot(int k){access(k),splay(k),rev(k);} void link(int x,int y){makeroot(x),tree[x].fa=y,fa2[find2(x)]=find2(y);} ll C(int x,int y){return 1ll*x*(x-1)/2;} void dfs(int k,int x) { if (!k) return; if (find(k)!=x) { ans-=C(size[x],2);ans-=C(size[find(k)],2); size[x]+=size[find(k)]; ans+=C(size[x],2); fa[find(k)]=x; } dfs(lson,x),dfs(rson,x); } void addedge(int x,int y) { if (find2(x)!=find2(y)) link(x,y); else { makeroot(x),access(y),splay(y); dfs(tree[y].ch[0],y);tree[y].ch[0]=0; } } int main() { int T=read(); while (T--) { n=read(),m=read(); ans=0;ll tot=0; for (int i=1;i<=n;i++) fa[i]=i,fa2[i]=i,size[i]=1,tree[i].ch[0]=tree[i].ch[1]=tree[i].fa=tree[i].rev=0; for (int i=1;i<=m;i++) { int x=find(read()),y=find(read()); if (x!=y) addedge(x,y); tot^=i*ans; } cout<<tot<<endl; } return 0; }
D:考慮暴力,即枚舉每道題的作法,而後給每道題一個貪心順序,大約是T*86*6!的過不掉。注意到值域很小,考慮以此dp,並把貪心順序放到外層,即f[S][i][j]表示已作完S集合的題目,第一我的最後作題時刻爲i,第二我的最後作題時刻爲j時,第三我的最先的最後作題時刻,轉移考慮下一步貪心的作哪一個題以及怎麼作便可,大約是T*26*1802*6*8。雖然複雜度看起來仍然很是爆炸,但容易發現不少狀態都是沒法到達的,轉移時先看一下當前狀態dp值是否合法便可,這樣內部的6*8幾乎能夠無視。spa
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int a[10][10],f[1<<6][200][200],size[1<<6]; int main() { int T=read(); for (int i=1;i<(1<<6);i++) size[i]=size[i^(i&-i)]+1; while (T--) { for (int i=0;i<6;i++) cin>>a[i][1]>>a[i][2]>>a[i][4]>>a[i][3]>>a[i][5]>>a[i][6]>>a[i][7]; memset(f,42,sizeof(f));f[0][0][0]=0; int ans=0,ans2=0; for (int i=0;i<(1<<6);i++) { for (int j=0;j<=180;j++) for (int k=0;k<=180;k++) if (f[i][j][k]<=180) { for (int x=0;x<6;x++) if (!(i&(1<<x))) { int u=i|(1<<x); f[u][min(j+a[x][1],181)][k]=min(f[u][min(j+a[x][1],181)][k],f[i][j][k]); f[u][j][min(k+a[x][2],181)]=min(f[u][j][min(k+a[x][2],181)],f[i][j][k]); f[u][j][k]=min(f[u][j][k],f[i][j][k]+a[x][4]); int v=min(max(max(j,k),f[i][j][k])+a[x][7],181); f[u][v][v]=min(f[u][v][v],v); v=min(max(j,k)+a[x][3],181); f[u][v][v]=min(f[u][v][v],f[i][j][k]); v=min(max(j,f[i][j][k])+a[x][5],181); f[u][v][k]=min(f[u][v][k],v); v=min(max(k,f[i][j][k])+a[x][6],181); f[u][j][v]=min(f[u][j][v],v); } } } for (int i=1;i<(1<<6);i++) for (int j=0;j<=180;j++) for (int k=0;k<=180;k++) if (f[i][j][k]<=180) { if (size[i]>ans||size[i]==ans&&max(max(j,f[i][j][k]),k)<ans2) { ans=size[i]; ans2=max(max(j,f[i][j][k]),k); } } cout<<ans<<' '<<ans2<<endl; } return 0; }
E:考慮處理出先後綴求LIS用的單調棧。注意到修改一個數後LIS要麼不變要麼+1,因此維護出有用的先後綴每一對LIS的拼接結果便可。注意還要考慮修改後LIS仍不包含當前數的狀況。代碼有大量冗餘。htm
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<set> using namespace std; #define ll long long #define N 100010 #define inf 1000000010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,a[N],ans,p[N],q[N],f[N][2],g[N][2],stkx[N],stky[N],cnt; multiset<int> q1,q2; int main() { int T=read(); while (T--) { n=read(); for (int i=1;i<=n;i++) a[i]=read(); q[0]=inf;for (int i=1;i<=n;i++) q[i]=-1; g[n+1][0]=0,g[n+1][1]=inf;ans=0; for (int i=n;i>=1;i--) { int l=0,r=ans; while (l<=r) { int mid=l+r>>1; if (q[mid]>a[i]) g[i][0]=mid+1,l=mid+1; else r=mid-1; } stkx[i]=g[i][0],stky[i]=q[g[i][0]]; g[i][1]=q[g[i][0]]=a[i]; ans=max(ans,g[i][0]); } cnt=0;q1.clear(),q2.clear(); p[0]=-1;for (int i=1;i<=n;i++) p[i]=inf; if (q[ans]>p[0]) cnt++; if (q[ans]>p[0]+1) q1.insert(p[0]); if (q[ans-1]>p[0]+1) q2.insert(p[0]); f[0][0]=0,f[0][1]=-1; int mx=0; for (int i=1;i<=n;i++) { if (q[stkx[i]]>p[ans-stkx[i]]+1) q1.erase(q1.find(p[ans-stkx[i]])); if (ans>=stkx[i]+1) if (q[stkx[i]]>p[ans-stkx[i]-1]+1) q2.erase(q2.find(p[ans-stkx[i]-1])); if (q[stkx[i]]>p[ans-stkx[i]]) cnt--; q[stkx[i]]=stky[i]; if (q[stkx[i]]>p[ans-stkx[i]]+1) q1.insert(p[ans-stkx[i]]); if (ans>=stkx[i]+1) if (q[stkx[i]]>p[ans-stkx[i]-1]+1) q2.insert(p[ans-stkx[i]-1]); if (q[stkx[i]]>p[ans-stkx[i]]) cnt++; if (!q1.empty()) printf("%d %d\n",ans+1,(*q1.begin())+1); else if (cnt) printf("%d %d\n",ans,0); else printf("%d %d\n",ans,(*q2.begin())+1); int l=0,r=mx; while (l<=r) { int mid=l+r>>1; if (p[mid]<a[i]) f[i][0]=mid+1,l=mid+1; else r=mid-1; } mx=max(mx,f[i][0]); if (q[ans-f[i][0]]>p[f[i][0]]+1) q1.erase(q1.find(p[f[i][0]])); if (ans>=f[i][0]+1) if (q[ans-f[i][0]-1]>p[f[i][0]]+1) q2.erase(q2.find(p[f[i][0]])); if (q[ans-f[i][0]]>p[f[i][0]]) cnt--; f[i][1]=p[f[i][0]]=a[i]; if (q[ans-f[i][0]]>p[f[i][0]]+1) q1.insert(p[f[i][0]]); if (ans>=f[i][0]+1) if (q[ans-f[i][0]-1]>p[f[i][0]]+1) q2.insert(p[f[i][0]]); if (q[ans-f[i][0]]>p[f[i][0]]) cnt++; } } return 0; }
F:顯然求出每一個子集的最大面積後就能經過O(3n)的狀壓dp獲得答案。有一個結論是,要使面積最大,多邊形頂點必定共圓,證實沒怎麼懂。因而找出圓半徑就能夠了。容易想到二分,爲了肯定二分方向,先做一個以最長邊爲直徑的圓,分兩種狀況考慮:若全部邊覆蓋的圓心角之和>2π,圓半徑增大時覆蓋的圓心角會變小;若全部邊覆蓋的圓心角之和<2π,其中最長邊覆蓋的應該是優弧,圓半徑增大時覆蓋的圓心角會變大。以此二分便可。不知道爲啥就是過不了,棄了。blog
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<cassert> using namespace std; #define ll long long #define N 13 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int T,n,a[N],from[1<<N]; long double s[1<<N],f[1<<N]; const long double PI=acos(-1.0); long double A(long double r,long double a) { return 2*asin(a/2/r); } long double angle(long double k,int S,int op) { long double alpha=0; int mx=0;for (int i=0;i<n;i++) if (S&(1<<i)) mx=max(mx,a[i]); for (int i=0;i<n;i++) if (S&(1<<i)) if (op==1&&a[i]==mx) alpha+=2*PI-A(k,a[i]); else alpha+=A(k,a[i]); return alpha; } long double calc(long double k,int S,int op) { long double area=0; int mx=0;for (int i=0;i<n;i++) if (S&(1<<i)) mx=max(mx,a[i]); for (int i=0;i<n;i++) if (S&(1<<i)) { if (a[i]==mx&&op==1) area-=a[i]*sqrt(k*k-(a[i]/2.0)*(a[i]/2.0))/2; else area+=a[i]*sqrt(k*k-(a[i]/2.0)*(a[i]/2.0))/2; } return area; } int main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif T=read(); while (T--) { n=read(); for (int i=0;i<n;i++) a[i]=read(); for (int i=0;i<(1<<n);i++) { s[i]=0; int S=0,mx=0; for (int j=0;j<n;j++) if (i&(1<<j)) S+=a[j],mx=max(mx,a[j]); if (2*mx<S) { int op=angle(mx/2.0,i,0)<=2*PI;//op=1時 最長邊的角用2π去減 此時角度之和<2π long double l=mx/2.0,r=1000000,ans=l; for (int j=1;j<=100;j++) { long double mid=(l+r)/2; if (op==(angle(mid,i,op)<=2*PI)) ans=mid,l=mid; else r=mid; } s[i]=calc(ans,i,op); } } f[0]=1; double qwq=0;int id=0; for (int i=1;i<(1<<n);i++) { from[i]=0;f[i]=0; for (int j=i;j;j=j-1&i) if (s[j]*f[i^j]>f[i]) f[i]=s[j]*f[i^j],from[i]=i^j; if (f[i]>qwq) qwq=f[i],id=i; } printf("%.10lf\n",qwq); int cnt=0,b[N]; for (int i=id;i;i=from[i]) { int x=i^from[i],s=0,mx=0; for (int j=0;j<n;j++) if (x&(1<<j)) s+=a[j],mx=max(mx,a[j]); if (2*mx<s) b[++cnt]=x; } cout<<cnt<<endl; for (int i=1;i<=cnt;i++) { int s=0; for (int j=0;j<n;j++) if (b[i]&(1<<j)) s++; cout<<s<<' '; for (int j=0;j<n;j++) if (b[i]&(1<<j)) cout<<a[j]<<' '; cout<<endl; } } return 0; }
沒有小裙子嗚嗚嗚ci