A题。算是个模拟。华丽丽的写了100行,代码能力还是不行。
B题。凸包加dp,不会。
C题。字符串,kmp。操作是能将字符串一分为二然后交换位置。操作的次数是无限的。
发现将这两个字符串分别首尾相接他两是一样的。。于是将b+=b;然后kmp跑a在b中的匹配。
D题。并查集。比赛的时候想到并查集了。但是退盟操作没有想到比较好的方法。
每次退盟的时候,可以给这个国家一个新的id,相当于新加了一个独立的点,可以默认为已经将这个点从原来的盟国中删除掉了。
#include<cstring> #include<iostream> #include<cstdio> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<string> #include<cstdlib> #include<string> #include<map> using namespace std; #define re freopen("in.txt","r",stdin) #define we freopen("out.txt","w",stdout) #define maxn 100100*10 #define maxm 200005 #define ll long long #define ld long double int fa[maxn]; int n; int id[maxn]; void ini() { for(int i=0; i<maxn; i++) fa[i]=i,id[i]=i; } int Fin(int a) { if(fa[a]==a)return fa[a]; fa[a]=Fin(fa[a]); return fa[a]; } void Uni(int a,int b) { a=Fin(a); b=Fin(b); if(a==b)return; fa[a]=b; } bool vis[maxn]; int main() { int a,b; // re; int m; int nc=1; while(~scanf("%d%d",&n,&m)&&(n+m)) { char s[11]; ini(); int tot=n; while(m--) { scanf("%s",s); if(s[0]=='M') { scanf("%d%d",&a,&b); Uni(id[a],id[b]); } else if(s[0]=='S') { scanf("%d",&a); id[a]=tot++; } } int ans=0; memset(vis,false,sizeof(vis)); for(int i=0; i<n; i++) { int t=Fin(id[i]); if(!vis[t])vis[t]=true,ans++; } printf("Case #%d: %d\n",nc++,ans); } return 0; }
E题。比较简单的DP。因为我会。。
有n个台阶,每一次可以跨x或者y个台阶。问必须经过a和b两个台阶的方案数有多少。
用dp[i]表示到第i个台阶的方案数。那么要求的答案就是dp[a]*dp[b-a]*dp[n-b];相当于分解为三段小去走。
WA一次因为没看题下面的mod10……07;
#include<cstring> #include<iostream> #include<cstdio> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<string> #include<cstdlib> #include<string> #include<map> using namespace std; #define re freopen("in.txt","r",stdin) #define we freopen("out.txt","w",stdout) #define maxn 10011 #define maxm maxn*maxn/2 #define ll long long #define ld long double #define mod 1000000007 ll dp[maxn]; int main() { int nc; //re; int n; int x,y,a,b; while(5==scanf("%d%d%d%d%d",&n,&x,&y,&a,&b)){ memset(dp,0,sizeof(dp)); dp[0]=1; if(a>b)swap(a,b); for(int j=1;j<=n;j++){ if(j-x>=0) dp[j]=(dp[j]+dp[j-x])%mod; if(j-y>=0&&x!=y) dp[j]=(dp[j-y]+dp[j])%mod; } printf("%lld\n",(dp[a]%mod*dp[b-a]%mod)%mod*dp[n-b]%mod); } return 0; }
F题。树dp。以前一个树dp的题也没做过。看到之后就傻了。于是瞎搞。。一直超时。。记忆化搜索也不错。于是改改改改。但是连样例都过不了。
要回寝室了。于是交一发,结果都没看,想着就是回了寝室接着搞。。但是回去打开一看居然过了。。尼玛。逗我呢。
#include<cstring> #include<iostream> #include<cstdio> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<string> #include<cstdlib> #include<string> #include<map> using namespace std; #define re freopen("in.txt","r",stdin) #define we freopen("out.txt","w",stdout) #define maxn 200005 #define maxm 200005 #define ll long long #define ld long double struct pp { int u,v; int tt[6]; int next; }edge[maxm]; int head[maxn]; int vis[maxn]; int cnt; void add(int u,int v,int a,int b,int c,int d) { edge[cnt].u=u; edge[cnt].v=v; edge[cnt].next=head[u]; edge[cnt].tt[0]=a; edge[cnt].tt[1]=b; edge[cnt].tt[2]=c; edge[cnt].tt[3]=d; head[u]=cnt++; } int aa[maxn],bb[maxn]; int dp[maxn][2]; bool dvis[maxn][2]; int dfs(int n,int type) { int sum=0; if(dvis[n][type])return dp[n][type]; for(int i=head[n];~i;i=edge[i].next){ int v=edge[i].v; if(vis[v])continue; if(type==0) sum+=min(dfs(v,1)+edge[i].tt[1]+bb[v],aa[v]+dfs(v,0)+edge[i].tt[0]); else sum+=min(dfs(v,1)+edge[i].tt[3]+bb[v],aa[v]+dfs(v,0)+edge[i].tt[2]); } dp[n][type]=sum; dvis[n][type]=1; return sum; } int main() { // re; int nc; scanf("%d",&nc); while(nc--){ int n; scanf("%d",&n); memset(head,-1,sizeof(head)); cnt=0; memset(vis,false,sizeof(vis)); memset(dvis,false,sizeof(dvis)); for(int i=1;i<=n;i++) scanf("%d",&aa[i]); for(int i=1;i<=n;i++) scanf("%d",&bb[i]); int m=n-1; int a,b,c,d,e,f; while(m--){ scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f); add(a,b,c,d,e,f); } vis[1]=true; int ans=min(dfs(1,0)+aa[1],dfs(1,1)+bb[1]); printf("%d\n",ans); } return 0; }
F、G不会。日后补充。